﻿// 注意：请勿在 app 声明之前注册路由。set-super 路由定义已移动到文件后部（app 初始化之后）。
const express = require("express");
const path = require("path");
// 优先从当前 Server 目录加载 .env，避免工作目录不同导致未读取
try {
  const dotenv = require('dotenv');
  dotenv.config({ path: path.join(__dirname, '../.env') });
  // 再尝试加载默认路径（若需要覆盖）
  // dotenv.config();

} catch (_) {
}
const { User, Post, Comment, Like, ExpRecord, Message, Feedback, IdentityVerification, IdentityAuditLog } = require('./db');
const ServiceConfig = require('./Model/ServiceConfig');
const Config = require('./Model/Config');
const userLevelService = require('./services/userLevelService');
const scheduleService = require('./services/scheduleService');
const axios = require('axios');
const crypto = require('crypto');
const request = require("request");
const multer = require("multer");
const fs = require("fs");
const app = express();
const TENCENT_MAP_KEY = process.env.TENCENT_MAP_KEY || '';
const TENCENT_MAP_SK = process.env.TENCENT_MAP_SK || '';

function buildQueryStringEncoded(params) {
  const keys = Object.keys(params).sort();
  return keys.map(k => `${k}=${encodeURIComponent(params[k])}`).join('&');
}

function buildTencentSig(pathname, params, sk) {
  // 腾讯地图WebService签名算法（按官方文档）：
  // 1. 参数按key字母顺序排序
  // 2. 拼接为 key1=value1&key2=value2 格式（原始值，不编码）
  // 3. 拼接: pathname + "?" + 排序参数串 + SK
  // 4. 计算MD5（小写）
  
  const sortedKeys = Object.keys(params).sort();
  const queryPairs = sortedKeys.map(key => `${key}=${params[key]}`);
  const queryString = queryPairs.join('&');
  
  const raw = `${pathname}?${queryString}${sk}`;

  
  return crypto.createHash('md5').update(raw).digest('hex');
}

// 配置CORS和安全头
app.use((req, res, next) => {
  // 允许跨域访问
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
  
  // 设置缓存控制头（对图片等静态资源）
  if (req.url.includes('/File/Images/')) {
    res.header('Cache-Control', 'public, max-age=86400'); // 24小时缓存
    res.header('Access-Control-Max-Age', '86400');
  }
  
  // 处理预检请求
  if (req.method === 'OPTIONS') {
    res.sendStatus(200);
  } else {
    next();
  }
});

// ===================== 客服二维码上传至 /File/Images/Service，命名为 ServiceCode.jpg =====================
const serviceCodeStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const dir = path.join(__dirname, '../File/Images/Service');
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    cb(null, dir);
  },
  filename: function (req, file, cb) {
    // 固定文件名为 ServiceCode.jpg
    cb(null, 'ServiceCode.jpg');
  }
});

const uploadServiceCode = multer({
  storage: serviceCodeStorage,
  limits: { fileSize: 10 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    if (file.mimetype && file.mimetype.startsWith('image/')) return cb(null, true);
    return cb(new Error('只允许上传图片文件!'), false);
  }
});

// 上传客服二维码
app.post('/api/service/code/upload', uploadServiceCode.single('file'), checkAdminPermission, async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ code: 400, message: '请选择要上传的文件', data: null });
    }
    
    // 文件已经被multer保存为 ServiceCode.jpg（如果存在旧文件会被自动覆盖）
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const url = `${protocol}://${host}/File/Images/Service/ServiceCode.jpg`;
    
    // 更新数据库中的qrcodeUrl
    const { openid } = req.body;
    const serviceConfig = await ServiceConfig.findOne({});
    if (serviceConfig) {
      serviceConfig.qrcodeUrl = '/File/Images/Service/ServiceCode.jpg';
      serviceConfig.updatedAt = new Date();
      serviceConfig.updatedBy = openid;
      await serviceConfig.save();
    } else {
      // 如果不存在配置，创建一个新的
      await ServiceConfig.create({
        qrcodeUrl: '/File/Images/Service/ServiceCode.jpg',
        updatedBy: openid
      });
    }
    
    return res.json({ 
      code: 0, 
      message: '上传成功', 
      data: { 
        url, 
        filename: 'ServiceCode.jpg',
        qrcodeUrl: '/File/Images/Service/ServiceCode.jpg'
      } 
    });
  } catch (e) {
    console.error('上传客服二维码失败:', e);
    return res.status(500).json({ code: 500, message: '上传失败', data: null });
  }
});

// 获取/保存客服配置
app.get('/api/service/config', async (req, res) => {
  const config = await ServiceConfig.findOne({}) || {};
  return res.json({ code: 0, message: 'success', data: config });
});

app.post('/api/service/config', (req, res) => {
  // 手动解析原始数据
  let rawData = '';
  
  req.on('data', chunk => {
    rawData += chunk.toString();
  });
  
  req.on('end', async () => {
    try {
      let parsedData = {};
      let openid;
      
      // 尝试解析JSON数据
      if (rawData) {
        try {
          parsedData = JSON.parse(rawData);
          openid = parsedData.openid;
        } catch (parseError) {
          return res.status(400).json({ code: 400, message: '数据格式错误', data: null });
        }
      }
      
      // 如果JSON解析失败，尝试从req.body获取
      if (!openid && req.body && req.body.openid) {
        openid = req.body.openid;
        parsedData = req.body;
      }
      
      // 最后尝试从query获取
      if (!openid && req.query && req.query.openid) {
        openid = req.query.openid;
      }
      
      if (!openid) {
        return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
      }
      
      // 检查管理员权限
      const user = await User.findOne({ openid });
      
      if (!user) {
        return res.status(404).json({ code: 404, message: '用户不存在', data: null });
      }
      
      if (!user.isAdmin && !user.isSuperAdmin) {
        return res.status(403).json({ code: 403, message: '权限不足，仅限管理员操作', data: null });
      }
      
      // 提取客服配置数据
      const { wechatId, workTime, workTimeStart, workTimeEnd, phone, email, qrcodeUrl } = parsedData;
      
      const config = await ServiceConfig.findOne({});
      if (config) {
        config.wechatId = wechatId ?? config.wechatId;
        // 兼容：优先写入拆分字段
        if (typeof workTimeStart === 'string') config.workTimeStart = workTimeStart;
        if (typeof workTimeEnd === 'string') config.workTimeEnd = workTimeEnd;
        // 同步生成合并显示字段（例如 09:00-18:00）
        if (config.workTimeStart && config.workTimeEnd) {
          config.workTime = `${config.workTimeStart}-${config.workTimeEnd}`;
        } else if (typeof workTime === 'string') {
          // 后备：如果旧字段传入，则按旧逻辑覆盖
          config.workTime = workTime;
        }
        config.phone = phone ?? config.phone;
        config.email = email ?? config.email;
        config.qrcodeUrl = qrcodeUrl ?? config.qrcodeUrl;
        config.updatedAt = new Date();
        config.updatedBy = openid || config.updatedBy;
        await config.save();
        return res.json({ code: 0, message: '保存成功', data: config });
      } else {
        // 新建：同时写入拆分字段与合并字段
        const newDoc = {
          wechatId,
          workTimeStart: workTimeStart || '',
          workTimeEnd: workTimeEnd || '',
          workTime: (workTimeStart && workTimeEnd) ? `${workTimeStart}-${workTimeEnd}` : (workTime || ''),
          phone,
          email,
          qrcodeUrl,
          updatedBy: openid
        };
        const created = await ServiceConfig.create(newDoc);
        return res.json({ code: 0, message: '保存成功', data: created });
      }
    } catch (e) {
      console.error('保存客服配置失败:', e);
      return res.status(500).json({ code: 500, message: '保存失败', data: null });
    }
  });
});

/**
 * 管理员删除反馈（软删除）
 * DELETE /api/admin/feedbacks/:id
 */
app.delete('/api/admin/feedbacks/:id', async (req, res) => {
  // 管理员校验（User.isAdmin=true）
  try {
    const { openid } = req.query;
    if (!openid) {
      return res.status(401).json({ code: 401, message: '未提供管理员身份(openid)' });
    }
    const adminUser = await User.findOne({ openid }).lean();
    if (!adminUser || (!adminUser.isAdmin && !adminUser.isSuperAdmin)) {
      return res.status(403).json({ code: 403, message: '无管理员权限' });
    }
  } catch (e) {
    return res.status(500).json({ code: 500, message: '管理员校验失败' });
  }

  try {
    const { id } = req.params;
    const feedback = await Feedback.findById(id);
    if (!feedback) {
      return res.status(404).json({ code: 404, message: '反馈不存在', data: null });
    }

    // 管理端软删除：仅标记 adminDeleted=true；若用户端也已删除，则进行物理清除
    feedback.adminDeleted = true;
    feedback.updateTime = new Date();
    await feedback.save();

    if (feedback.userDeleted) {
      await Feedback.deleteOne({ _id: id });
      return res.json({ code: 0, message: '删除成功（已彻底清除）', data: null });
    }

    res.json({ code: 0, message: '删除成功（管理端隐藏）', data: null });
  } catch (error) {
    console.error('管理员删除反馈失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 逆地理解析：服务端代理腾讯地图，避免在前端暴露Key/SK
app.get('/api/utils/reverse-geocode', async (req, res) => {
  try {
    const { lat, lng } = req.query;
    if (!lat || !lng) {
      return res.status(400).json({ code: 400, message: 'lat/lng 不能为空', data: null });
    }

    // 无Key时降级为兜底数据，避免前端500报错
    if (!TENCENT_MAP_KEY) {
      return res.json({
        code: 0,
        message: 'fallback: map key not configured',
        data: { name: '暂无地址', address: '', raw: null }
      });
    }

    // 腾讯地图WebService API - 逆地理编码（按官方文档使用签名）
    const pathname = '/ws/geocoder/v1/';
    const params = {
      key: TENCENT_MAP_KEY,
      location: `${lat},${lng}`,
      get_poi: 1,
      coord_type: 5
    };
    
    let url;
    if (TENCENT_MAP_SK) {
      // 有SK则使用签名
      const sig = buildTencentSig(pathname, params, TENCENT_MAP_SK);
      const encodedQuery = buildQueryStringEncoded(params);
      url = `https://apis.map.qq.com${pathname}?${encodedQuery}&sig=${sig}`;
    } else {
      // 无SK则简单拼接
      const encodedQuery = buildQueryStringEncoded(params);
      url = `https://apis.map.qq.com${pathname}?${encodedQuery}`;
    }
    
    if (!process.env.SUPPRESS_REVERSE_GEOCODE_LOG) {
      console.log('[reverse-geocode] request URL:', url);
    }
    
    try {
      const resp = await axios.get(url, { timeout: 5000 });
      if (resp.data && resp.data.status === 0) {
        const r = resp.data.result || {};
        const pois = r.pois || [];
        const name = (pois[0] && pois[0].title) || r.formatted_addresses?.recommend || r.address || '';
        return res.json({ code: 0, message: 'success', data: { name, address: r.address || '', raw: r } });
      }
      if (!process.env.SUPPRESS_REVERSE_GEOCODE_LOG) {
        console.warn('[reverse-geocode] request failed, status:', resp.data?.status, 'message:', resp.data?.message);
      }
    } catch (e) {
      if (!process.env.SUPPRESS_REVERSE_GEOCODE_LOG) {
        console.warn('[reverse-geocode] request error:', e?.message || e);
      }
    }

    // 仍失败则兜底
    return res.json({ code: 0, message: 'fallback: geocoder failed', data: { name: '暂无地址', address: '', raw: null } });
  } catch (err) {
    console.error('reverse-geocode error:', err?.message || err);
    // 网络/解析异常同样降级为成功返回
    return res.json({ code: 0, message: 'fallback: server error', data: { name: '暂无地址', address: '', raw: null } });
  }
});

// 解析 JSON 和 form-data - 确保在所有路由之前
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));



// 检查管理员权限的中间件（根据 User 模型中的 isAdmin / isSuperAdmin 布尔值判断）
async function checkAdminPermission(req, res, next) {
  try {
    // openid 可能来自 body（POST/DELETE）或 query（GET）
    const openid = (req.body && req.body.openid) || (req.query && req.query.openid);
    
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }

    // 从数据库查询用户信息
    const user = await User.findOne({ openid });
    
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }

    // 按模型字段校验管理员权限
    if (user.isAdmin || user.isSuperAdmin) {
      req.user = user;
      return next();
    }

    return res.status(403).json({ code: 403, message: '权限不足，仅限管理员操作', data: null });
  } catch (error) {
    console.error('权限验证失败:', error);
    return res.status(500).json({ code: 500, message: '权限验证失败', data: null });
  }
}

// 身份认证检查中间件
async function checkIdentityVerification(req, res, next) {
  try {
    // 首先检查身份审核功能是否开启
    const auditConfig = await Config.findOne({ type: 'system', key: 'identityAuditRequired' });
    const identityAuditEnabled = auditConfig ? auditConfig.value : true; // 默认开启
    
    // 如果身份审核功能关闭，直接通过
    if (!identityAuditEnabled) {
      return next();
    }
    
    // 如果身份审核功能开启，检查用户身份认证状态
    const openid = (req.body && req.body.openid) || (req.query && req.query.openid);
    if (!openid) {
      return res.status(400).json({ 
        code: 400, 
        message: 'openid不能为空', 
        data: null 
      });
    }
    
    // 查找用户的身份认证记录
    const verification = await IdentityVerification.findOne({ openid }).sort({ submitTime: -1 });
    
    // 如果没有认证记录或认证未通过，返回错误
    if (!verification || verification.status !== 'approved') {
      return res.status(403).json({ 
        code: 403, 
        message: '需要完成身份认证后才能进行此操作', 
        data: { needVerification: true }
      });
    }
    
    next();
  } catch (error) {
    console.error('检查身份认证状态失败:', error);
    return res.status(500).json({ 
      code: 500, 
      message: '服务器错误', 
      data: null 
    });
  }
}

// 仅超级管理员权限检查
async function checkSuperAdminPermission(req, res, next) {
  try {
    const openid = (req.body && req.body.openid) || (req.query && req.query.openid);
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    if (user.isSuperAdmin) {
      req.user = user;
      return next();
    }
    return res.status(403).json({ code: 403, message: '权限不足，仅限超级管理员操作', data: null });
  } catch (error) {
    console.error('超级管理员权限验证失败:', error);
    return res.status(500).json({ code: 500, message: '权限验证失败', data: null });
  }
}

// 检查客服二维码是否存在的接口
app.get('/api/service/code/check', (req, res) => {
  const filePath = path.join(__dirname, '../File/Images/Service/ServiceCode.jpg');
  const exists = fs.existsSync(filePath);
  
  res.json({
    code: 0,
    message: 'success',
    data: {
      exists,
      qrcodeUrl: exists ? '/File/Images/Service/ServiceCode.jpg' : '/File/Images/Service/customer-service-qr.jpg'
    }
  });
});

// 新增：检查 Logo 是否存在
app.get('/api/service/logo/check', (req, res) => {
  const filePath = path.join(__dirname, '../File/Images/Service/logo.jpg');
  const exists = fs.existsSync(filePath);
  res.json({
    code: 0,
    message: 'success',
    data: {
      exists,
      logoUrl: exists ? '/File/Images/Service/logo.jpg' : ''
    }
  });
});

// 专门处理 ServiceCode.jpg 的请求，必须在静态文件中间件之前
app.get('/File/Images/Service/ServiceCode.jpg', (req, res) => {
  const filePath = path.join(__dirname, '../File/Images/Service/ServiceCode.jpg');
  
  console.log('请求ServiceCode.jpg，文件路径:', filePath);
  console.log('文件是否存在:', fs.existsSync(filePath));
  
  // 检查文件是否存在
  if (fs.existsSync(filePath)) {
    // 设置正确的Content-Type
    res.setHeader('Content-Type', 'image/jpeg');
    res.sendFile(filePath, (err) => {
      if (err) {
        console.error('发送文件失败:', err);
        res.status(500).json({ 
          code: 500, 
          message: '文件读取失败', 
          data: null 
        });
      }
    });
  } else {
    // 文件不存在，返回404
    console.log('ServiceCode.jpg文件不存在，返回404');
    res.status(404).json({ 
      code: 404, 
      message: '客服二维码未上传', 
      data: null 
    });
  }
});

// 新增：上传 Logo（固定为 logo.jpg）
const logoStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const dir = path.join(__dirname, '../File/Images/Service');
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    cb(null, dir);
  },
  filename: function (req, file, cb) {
    cb(null, 'logo.jpg');
  }
});
const uploadLogo = multer({
  storage: logoStorage,
  limits: { fileSize: 10 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    if (file.mimetype && file.mimetype.startsWith('image/')) return cb(null, true);
    return cb(new Error('只允许上传图片文件!'), false);
  }
});

app.post('/api/service/logo/upload', uploadLogo.single('file'), checkAdminPermission, async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ code: 400, message: '请选择要上传的文件', data: null });
    }
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const url = `${protocol}://${host}/File/Images/Service/logo.jpg`;
    return res.json({ code: 0, message: '上传成功', data: { url, filename: 'logo.jpg' } });
  } catch (e) {
    console.error('上传Logo失败:', e);
    return res.status(500).json({ code: 500, message: '上传失败', data: null });
  }
});

// 配置静态文件服务 - 统一配置
app.use('/File', express.static(path.join(__dirname, '../File'), {
  maxAge: '1d', // 1天缓存
  setHeaders: (res, path) => {
    // 为图片文件设置正确的Content-Type
    if (path.endsWith('.jpg') || path.endsWith('.jpeg')) {
      res.setHeader('Content-Type', 'image/jpeg');
    } else if (path.endsWith('.png')) {
      res.setHeader('Content-Type', 'image/png');
    } else if (path.endsWith('.gif')) {
      res.setHeader('Content-Type', 'image/gif');
    } else if (path.endsWith('.webp')) {
      res.setHeader('Content-Type', 'image/webp');
    }
  }
}));

// 兼容旧的路径配置
app.use('/File/Images/Avatar', express.static(path.join(__dirname, '../File/Images/Avatar')));

// 配置文件上传
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const uploadDir = path.join(__dirname, '../File/Images/Avatar');
    // 确保目录存在
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    // 生成唯一文件名，保留原始扩展名
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    
    // 确保获取正确的原始扩展名
    let ext = path.extname(file.originalname).toLowerCase();
    
    // 如果没有扩展名，根据mimetype补充
    if (!ext) {
      if (file.mimetype === 'image/jpeg') ext = '.jpg';
      else if (file.mimetype === 'image/png') ext = '.png';
      else if (file.mimetype === 'image/gif') ext = '.gif';
      else if (file.mimetype === 'image/webp') ext = '.webp';
      else ext = '.jpg'; // 默认扩展名
    }
    
    console.log('上传文件信息:', {
      originalName: file.originalname,
      mimetype: file.mimetype,
      detectedExtension: ext,
      newFilename: `avatar-${uniqueSuffix}${ext}`
    });
    
    cb(null, `avatar-${uniqueSuffix}${ext}`);
  }
});

const upload = multer({ 
  storage: storage,
  limits: {
    fileSize: 5 * 1024 * 1024, // 限制5MB
  },
  fileFilter: function (req, file, cb) {
    // 只允许图片格式
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('只允许上传图片文件!'), false);
    }
  }
});

// 配置帖子媒体文件上传
const postMediaStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const { openid } = req.body;
    // 为每个用户创建单独的文件夹
    const uploadDir = path.join(__dirname, '../File/Images/PostImage', openid || 'anonymous');
    
    // 确保目录存在
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    // 生成唯一文件名，保留原始扩展名
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    
    // 确保获取正确的原始扩展名
    let ext = path.extname(file.originalname).toLowerCase();
    
    // 如果没有扩展名，根据mimetype补充
    if (!ext) {
      if (file.mimetype === 'image/jpeg') ext = '.jpg';
      else if (file.mimetype === 'image/png') ext = '.png';
      else if (file.mimetype === 'image/gif') ext = '.gif';
      else if (file.mimetype === 'image/webp') ext = '.webp';
      else if (file.mimetype === 'video/mp4') ext = '.mp4';
      else if (file.mimetype === 'video/quicktime') ext = '.mov';
      else ext = '.jpg'; // 默认扩展名
    }
    
    console.log('上传帖子媒体文件信息:', {
      originalName: file.originalname,
      mimetype: file.mimetype,
      detectedExtension: ext,
      newFilename: `post-${uniqueSuffix}${ext}`
    });
    
    cb(null, `post-${uniqueSuffix}${ext}`);
  }
});

const uploadPostMedia = multer({ 
  storage: postMediaStorage,
  limits: {
    fileSize: 50 * 1024 * 1024, // 限制50MB
  },
  fileFilter: function (req, file, cb) {
    // 允许图片和视频格式
    if (file.mimetype.startsWith('image/') || file.mimetype.startsWith('video/')) {
      cb(null, true);
    } else {
      cb(new Error('只允许上传图片或视频文件!'), false);
    }
  }
});

// 配置微信小程序信息
const config = {
  appId: 'wxd4a47c612b973986',
  appSecret: '0c65b990f85d15facf86661fd26239db'
};

// 获取微信 access_token（简单直取，不做缓存；若需优化可引入内存缓存）
async function getAccessToken() {
  const url = 'https://api.weixin.qq.com/cgi-bin/token';
  const params = { grant_type: 'client_credential', appid: config.appId, secret: config.appSecret };
  const resp = await axios.get(url, { params });
  if (resp.data && resp.data.access_token) return resp.data.access_token;
  throw new Error(resp.data?.errmsg || 'get access_token failed');
}

// 登录
app.post('/login', async (req, res) => {
  console.log(req.body); // 打印出来看结构
  const { code } = req.body;
  try {
    // 3. 调用微信接口
    // 使用 axios 发起 GET 请求到微信的 jscode2session 接口
    const result = await axios.get('https://api.weixin.qq.com/sns/jscode2session', {
      params: {
        // 小程序的 AppID
        appid: config.appId,
        // 小程序的 AppSecret
        secret: config.appSecret,
        // 登录时获取的 code，通过 req.body 传入
        js_code: code,
        // 授权类型，固定为 authorization_code
        grant_type: 'authorization_code'
      }
    });

    console.log('微信返回:', result.data); // 打印微信返回内容
    if (result.data.openid) {
      res.json({
        code: 0,
        message: 'success',
        data: {
          openid: result.data.openid,
          session_key: result.data.session_key
        }
      });
    } else {
      res.json({
        code: result.data.errcode || 5000,
        message: result.data.errmsg || '微信接口调用失败',
        data: null
      });
    }
  } catch (error) {
    console.error('获取openid失败:', error?.response?.data || error.message);
    res.status(500).json({ code: 5000, message: '获取用户信息失败' });
  }
});

// 查询或创建用户
app.post('/api/user/findOrCreateByOpenid', async (req, res) => {
  const { openid } = req.body;
  let { userInfo } = req.body;
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  try {
    let user = await User.findOne({ openid });
    let isNewUser = false;
    
    if (user) {
      console.log(`用户 ${openid} 登录成功`);
    } else {
      // 不存在则创建
      console.log(`创建新用户: ${openid}`);
      // 清洗头像：如果是空值或无效字符串，不写入，前端走默认头像
      if (!userInfo) userInfo = {};
      const raw = typeof userInfo.avatarUrl === 'string' ? userInfo.avatarUrl.trim() : userInfo.avatarUrl;
      if (!raw || raw === 'null' || raw === 'undefined') {
        delete userInfo.avatarUrl;
      }

      user = await User.create({ 
        openid, 
        userInfo,
        expInfo: {
          totalExp: 0,
          dailyExp: 0,
          dailyExpLimit: 200,
          level: 1,
          levelName: '见习观察者',
          lastUpdateDate: new Date()
        }
      });
      isNewUser = true;
    }
    
    // 获取用户等级信息
    const expData = await userLevelService.getUserExpInfo(openid);
    
    // 如果不是新用户，增加登录经验
    let expResult = null;
    if (!isNewUser) {
      try {
        // 查询今天是否已经获得过登录经验
        const today = new Date();
        today.setHours(0, 0, 0, 0);
        
        const loginRecords = await ExpRecord.find({
          openid,
          type: 'login',
          createdAt: { $gte: today }
        });
        
        // 如果今天还没获得过登录经验，则增加
        if (loginRecords.length === 0) {
          expResult = await userLevelService.recordExp(openid, 'login');
        }
      } catch (expError) {
        console.error('记录登录经验失败:', expError);
        // 登录经验记录失败不影响用户登录
      }
    }
    
    // 准备返回数据
    const responseData = {
      userInfo: user.userInfo,
      expInfo: expData.expInfo,
      levelInfo: expData.levelInfo,
      postCount: user.postCount || 0,
      openid: user.openid
    };
    
    // 如果有经验值增加结果，添加到返回数据中
    if (expResult) {
      responseData.expResult = {
        expAdded: expResult.expAdded,
        levelUp: expResult.levelUp
      };
    }
    
    return res.json({ 
      code: 0, 
      message: isNewUser ? 'created' : 'success', 
      data: responseData 
    });
  } catch (error) {
    console.error('findOrCreateByOpenid error:', error);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 上传头像接口
app.post('/api/user/uploadAvatar', upload.single('avatar'), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ 
        code: 400, 
        message: '请选择要上传的图片', 
        data: null 
      });
    }
    
    // 记录保存文件的详细信息
    console.log('保存文件信息:', {
      filename: req.file.filename,
      originalname: req.file.originalname,
      mimetype: req.file.mimetype,
      destination: req.file.destination,
      path: req.file.path,
      size: req.file.size
    });
    
    // 生成可访问的URL - 修复协议和域名问题
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const avatarUrl = `${protocol}://${host}/File/Images/Avatar/${req.file.filename}`;
    console.log('生成的头像URL:', avatarUrl);
    
    // 如果请求中包含openid，则更新用户头像信息
    const { openid } = req.body;
    console.log('上传头像请求的openid:', openid);
    
    if (openid) {
      const user = await User.findOne({ openid });
      console.log('查询到的用户:', user ? '存在' : '不存在');
      
      if (user) {
        // 删除旧头像文件
        if (user.userInfo && user.userInfo.avatarUrl) {
          try {
            // 从URL中提取文件名
            const oldAvatarUrl = user.userInfo.avatarUrl;
            const oldFilename = oldAvatarUrl.split('/').pop(); // 获取URL最后部分作为文件名
            
            if (oldFilename) {
              const oldFilePath = path.join(__dirname, '../File/Images/Avatar', oldFilename);
              
              // 检查文件是否存在
              if (fs.existsSync(oldFilePath)) {
                // 删除旧头像文件
                fs.unlinkSync(oldFilePath);
                console.log(`已删除用户 ${openid} 的旧头像: ${oldFilename}`);
              }
            }
          } catch (deleteError) {
            // 删除旧文件失败不影响上传新文件
            console.error('删除旧头像失败:', deleteError);
          }
        }
        
        // 确保userInfo对象存在
        if (!user.userInfo) {
          user.userInfo = {};
        }
        
        // 保存旧的昵称，以便更新帖子作者信息
        const oldNickName = user.userInfo.nickName || '用户';
        
        // 更新用户头像URL
        user.userInfo.avatarUrl = avatarUrl;
        
        // 标记userInfo字段已被修改（关键步骤！）
        user.markModified('userInfo');
        
        try {
          await user.save();
          console.log('成功保存用户头像URL:', avatarUrl);
          
          // 验证保存结果
          const verifyUser = await User.findOne({ openid });
          console.log('验证保存结果:', verifyUser.userInfo?.avatarUrl || '未保存成功');
          
          // 更新该用户发布的所有帖子中的作者信息
          try {
            const updateResult = await Post.updateMany(
              { openid: openid },
              { 
                $set: { 
                  'authorInfo.avatarUrl': avatarUrl,
                  'authorInfo.nickName': oldNickName
                } 
              }
            );
            
            console.log(`更新用户 ${openid} 的帖子作者信息结果:`, {
              matched: updateResult.matchedCount,
              modified: updateResult.modifiedCount
            });
          } catch (updateError) {
            console.error('更新帖子作者信息失败:', updateError);
          }
        } catch (saveError) {
          console.error('保存用户头像URL失败:', saveError);
        }
      } else {
        // 用户不存在，创建新用户
        console.log('用户不存在，创建新用户');
        const newUser = new User({
          openid,
          userInfo: {
            avatarUrl: avatarUrl
          }
        });
        await newUser.save();
        console.log('新用户已创建:', newUser);
      }
    } else {
      console.log('请求中没有提供openid，无法更新用户信息');
    }
    
    res.json({
      code: 0,
      message: '头像上传成功',
      data: {
        avatarUrl: avatarUrl,
        filename: req.file.filename
      }
    });
  } catch (error) {
    console.error('上传头像失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '上传头像失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 获取用户信息
app.get('/api/user/info', async (req, res) => {
  const { openid } = req.query;
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid参数不能为空', data: null });
  }
  
  try {
    // 查询用户信息
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }

    // 获取用户等级信息
    const expData = await userLevelService.getUserExpInfo(openid);
    if (!expData) {
      return res.status(404).json({ code: 404, message: '用户信息不完整', data: null });
    }

    // 准备返回数据，确保各字段有默认值
    // 以 service 返回为准，兜底时也使用当前全局上限
    const safeExpInfo = expData.expInfo || {
      totalExp: 0,
      dailyExp: 0,
      dailyExpLimit: require('./services/userLevelService').updateDailyExpLimit
        ? (await (async()=>{ try { return (await require('./services/userLevelService').getUserExpInfo(openid)).expInfo.dailyExpLimit || 50 } catch(_) { return 50 } })())
        : 50,
      level: 1,
      levelName: '见习观察者'
    };

    const responseData = {
      userInfo: user.userInfo || {},
      expInfo: safeExpInfo,
      levelInfo: expData.levelInfo,
      postCount: user.postCount || 0,
      openid: user.openid
    };
    
    res.json({
      code: 0,
      message: 'success',
      data: responseData
    });
  } catch (error) {
    console.error('获取用户信息失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 查询是否管理员
 * GET /api/user/is-admin?openid=xxx
 */
app.get('/api/user/is-admin', async (req, res) => {
  try {
    const { openid } = req.query;
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }
    const user = await User.findOne({ openid }).lean();
    const envAdmins = (process.env.ADMIN_OPENIDS || '')
      .split(',').map(s => s.trim()).filter(Boolean);
    const isAdmin = (user && (user.isAdmin || user.isSuperAdmin)) || envAdmins.includes(openid);
    const isSuperAdmin = !!(user && user.isSuperAdmin);
    return res.json({ code: 0, message: 'success', data: { isAdmin, isSuperAdmin } });
  } catch (e) {
    console.error('is-admin 查询失败:', e?.message || e);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 管理员获取用户列表
 * GET /api/admin/users?page=1&pageSize=10&keyword=xxx&openid=xxx
 */
app.get('/api/admin/users', async (req, res) => {
  try {
    const { openid, page = 1, pageSize = 10, keyword, role } = req.query;
    if (!openid) return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    const me = await User.findOne({ openid }).lean();
    const envAdmins = (process.env.ADMIN_OPENIDS || '').split(',').map(s => s.trim()).filter(Boolean);
    const isAdmin = (me && (me.isAdmin || me.isSuperAdmin)) || envAdmins.includes(openid);
    if (!isAdmin) return res.status(403).json({ code: 403, message: '无管理员权限', data: null });

    const p = parseInt(page);
    const s = parseInt(pageSize);
    const skip = (p - 1) * s;

    const query = {};
    if (keyword && keyword.trim()) {
      query.$or = [
        { openid: new RegExp(keyword.trim(), 'i') },
        { 'userInfo.nickName': new RegExp(keyword.trim(), 'i') }
      ];
    }
    if (role === 'admin') {
      query.$or = [
        ...(query.$or || []),
        { isAdmin: true }
      ];
    } else if (role === 'normal') {
      query.isAdmin = { $ne: true };
    }

    const users = await User.find(query)
      .select({ openid: 1, userInfo: 1, expInfo: 1, isAdmin: 1, isSuperAdmin: 1, postCount: 1 })
      .sort({ 'expInfo.totalExp': -1, _id: -1 })
      .skip(skip)
      .limit(s)
      .lean();

    const levelNameOf = (totalExp = 0) => {
      const levels = [
        { name: '见习观察者', min: 0 },
        { name: '初级浏览者', min: 100 },
        { name: '活跃用户', min: 300 },
        { name: '内容鉴赏者', min: 600 },
        { name: '资深评鉴员', min: 1000 }
      ];
      let current = levels[0];
      for (let i = levels.length - 1; i >= 0; i--) {
        if (totalExp >= levels[i].min) { current = levels[i]; break; }
      }
      return current.name;
    };

    const formatted = users.map(u => ({
      openid: u.openid,
      userInfo: {
        nickName: u.userInfo?.nickName || '用户',
        avatarUrl: u.userInfo?.avatarUrl || ''
      },
      expInfo: {
        totalExp: u.expInfo?.totalExp || 0
      },
      levelInfo: {
        name: levelNameOf(u.expInfo?.totalExp || 0)
      },
      isAdmin: !!u.isAdmin,
      isSuperAdmin: !!u.isSuperAdmin,
      postCount: u.postCount || 0
    }));

    const total = await User.countDocuments(query);
    return res.json({ code: 0, message: 'success', data: { users: formatted, total, hasMore: total > p * s } });
  } catch (e) {
    console.error('获取用户列表失败:', e?.message || e);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 管理员：切换用户管理员标记
 * POST /api/admin/users/toggle-admin
 * body: { openid, targetOpenid, makeAdmin: true|false }
 */
app.post('/api/admin/users/toggle-admin', async (req, res) => {
  try {
    const { openid, targetOpenid, makeAdmin } = req.body || {};
    if (!openid || !targetOpenid) return res.status(400).json({ code: 400, message: '参数不完整', data: null });
    const me = await User.findOne({ openid }).lean();
    const envAdmins = (process.env.ADMIN_OPENIDS || '').split(',').map(s => s.trim()).filter(Boolean);
    const isAdmin = (me && (me.isAdmin || me.isSuperAdmin)) || envAdmins.includes(openid);
    if (!isAdmin) return res.status(403).json({ code: 403, message: '无管理员权限', data: null });

    const updated = await User.findOneAndUpdate(
      { openid: targetOpenid },
      { $set: { isAdmin: !!makeAdmin } },
      { new: true }
    ).lean();
    if (!updated) return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    return res.json({ code: 0, message: 'success', data: { openid: updated.openid, isAdmin: !!updated.isAdmin, isSuperAdmin: !!updated.isSuperAdmin } });
  } catch (e) {
    console.error('切换管理员失败:', e?.message || e);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 超级管理员设置（系统唯一）
 * POST /api/admin/users/set-super
 * body: { openid, targetOpenid }
 */
app.post('/api/admin/users/set-super', async (req, res) => {
  try {
    const { openid, targetOpenid } = req.body || {};
    if (!openid || !targetOpenid) return res.status(400).json({ code: 400, message: '参数不完整', data: null });
    const me = await User.findOne({ openid }).lean();
    const envAdmins = (process.env.ADMIN_OPENIDS || '').split(',').map(s => s.trim()).filter(Boolean);
    const isSuper = me && me.isSuperAdmin;
    // 仅当前超级管理员或环境变量白名单允许设置
    if (!isSuper && !envAdmins.includes(openid)) return res.status(403).json({ code: 403, message: '无权限', data: null });

    // 取消所有人的超级管理员
    await User.updateMany({ isSuperAdmin: true }, { $set: { isSuperAdmin: false } });
    // 设置目标为超级管理员
    const updated = await User.findOneAndUpdate(
      { openid: targetOpenid },
      { $set: { isSuperAdmin: true, isAdmin: true } },
      { new: true }
    ).lean();
    if (!updated) return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    return res.json({ code: 0, message: 'success', data: { openid: updated.openid, isSuperAdmin: true } });
  } catch (e) {
    console.error('设置超级管理员失败:', e?.message || e);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 修改用户昵称
app.post('/api/user/nickname', async (req, res) => {
  const { openid, nickname } = req.body;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  
  if (!nickname || nickname.trim() === '') {
    return res.status(400).json({ code: 400, message: '昵称不能为空', data: null });
  }
  
  try {
    // 查询用户，获取当前头像URL
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    const avatarUrl = user.userInfo?.avatarUrl || '';
    
    // 使用findOneAndUpdate直接更新用户昵称
    const updatedUser = await User.findOneAndUpdate(
      { openid },
      { $set: { 'userInfo.nickName': nickname } },
      { new: true, upsert: false, runValidators: true }
    );
    
    if (!updatedUser) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    // 更新该用户发布的所有帖子中的作者信息
    try {
      const updateResult = await Post.updateMany(
        { openid: openid },
        { 
          $set: { 
            'authorInfo.nickName': nickname,
            'authorInfo.avatarUrl': avatarUrl
          } 
        }
      );
      
      console.log(`更新用户 ${openid} 的帖子作者信息结果:`, {
        matched: updateResult.matchedCount,
        modified: updateResult.modifiedCount
      });
    } catch (updateError) {
      console.error('更新帖子作者信息失败:', updateError);
    }
    
    res.json({
      code: 0,
      message: '昵称修改成功',
      data: {
        nickName: nickname
      }
    });
  } catch (error) {
    console.error('修改用户昵称失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 获取用户的帖子列表
app.get('/api/post/myPosts', async (req, res) => {
  const { openid, pageNum = 1, pageSize = 10, status } = req.query;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }

  // 将pageNum和pageSize转换为数字
  const page = parseInt(pageNum);
  const limit = parseInt(pageSize);
  const skip = (page - 1) * limit;
  
  try {
    // 构建查询条件
    const queryCondition = { openid };
    
    // 如果指定了状态，添加到查询条件
    if (status && status !== 'all') {
      // 状态映射：前端 active -> 后端 发布中，前端 ended -> 后端 结束
      let stateValue = status === 'active' ? '发布中' : '结束';
      queryCondition.state = stateValue;
    }
    
    // 查询总数
    const total = await Post.countDocuments(queryCondition);
    
    // 查询帖子列表
    const posts = await Post.find(queryCondition)
      .sort({ time: -1 }) // 按发布时间倒序排序
      .skip(skip)
      .limit(limit)
      .exec();
    
    // 格式化返回数据
    const formattedPosts = posts.map(post => ({
      id: post._id,
      title: post.title,
      content: post.content,
      status: post.state === '发布中' ? 'active' : 'ended', // 状态转换为前端需要的格式
      commentCount: post.commentCount || 0,
      likeCount: post.likeCount || 0,
      createTime: post.time, // 使用time字段作为createTime返回
      type: post.type,
      images: post.images || [],
      authorId: post.openid
    }));
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        list: formattedPosts,
        total: total,
        pageNum: page,
        pageSize: limit
      }
    });
  } catch (error) {
    console.error('获取用户帖子列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 结束发布（将帖子状态设为"结束"）
app.post('/api/post/end', async (req, res) => {
  try {
    const { openid, postId } = req.body || {};
    if (!openid || !postId) {
      return res.status(400).json({ code: 400, message: 'openid与postId均不能为空', data: null });
    }

    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ code: 404, message: '帖子不存在', data: null });
    }
    if (post.openid !== openid) {
      return res.status(403).json({ code: 403, message: '无权结束该帖子', data: null });
    }

    if (post.state === '结束') {
      return res.json({ code: 0, message: '已是结束状态', data: null });
    }

    post.state = '结束';
    await post.save();

    return res.json({ code: 0, message: '已结束发布', data: null });
  } catch (error) {
    console.error('结束发布失败:', error);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 提供静态访问帖子媒体文件
app.use('/File/Images/PostImage', express.static(path.join(__dirname, '../File/Images/PostImage')));

// 上传帖子媒体文件接口
app.post('/api/upload/media', uploadPostMedia.single('file'), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ 
        code: 400, 
        message: '请选择要上传的文件', 
        data: null 
      });
    }
    
    const { openid } = req.body;
    if (!openid) {
      return res.status(400).json({ 
        code: 400, 
        message: 'openid不能为空', 
        data: null 
      });
    }
    
    // 记录保存文件的详细信息
    console.log('保存帖子媒体文件信息:', {
      filename: req.file.filename,
      originalname: req.file.originalname,
      mimetype: req.file.mimetype,
      destination: req.file.destination,
      path: req.file.path,
      size: req.file.size
    });
    
    // 生成可访问的URL - 修复协议和域名问题
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const mediaUrl = `${protocol}://${host}/File/Images/PostImage/${openid}/${req.file.filename}`;
    console.log('生成的媒体文件URL:', mediaUrl);
    
    res.json({
      code: 0,
      message: '媒体文件上传成功',
      data: {
        url: mediaUrl,
        filename: req.file.filename
      }
    });
  } catch (error) {
    console.error('上传媒体文件失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '上传媒体文件失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 生成小程序码（不限制）
app.post('/api/miniprogram/qrcode', async (req, res) => {
  try {
    const { scene, page = 'pages/index/index', width = 430 } = req.body || {};
    if (!scene) return res.json({ code: 400, message: 'scene参数不能为空', data: null });
    if (scene.length > 32) return res.json({ code: 400, message: 'scene参数长度不能超过32个字符', data: null });

    const accessToken = await getAccessToken();
    const api = `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${accessToken}`;
    const resp = await axios({ method: 'POST', url: api, data: {
      scene,
      page,
      width: parseInt(width, 10) || 430,
      check_path: false,
      env_version: process.env.NODE_ENV === 'production' ? 'release' : 'trial'
    }, responseType: 'arraybuffer' });

    const contentType = resp.headers['content-type'] || '';
    if (contentType.includes('image')) {
      const base64 = Buffer.from(resp.data, 'binary').toString('base64');
      return res.json({ code: 0, message: 'success', data: { qrcode: `data:image/png;base64,${base64}`, scene, page } });
    }

    // 非图片时解析错误信息
    const text = Buffer.from(resp.data).toString();
    let err;
    try { err = JSON.parse(text); } catch { err = { errmsg: text }; }
    return res.json({ code: err.errcode || 500, message: err.errmsg || '生成小程序码失败', data: null });
  } catch (error) {
    console.error('生成小程序码失败:', error?.response?.data || error.message);
    return res.json({ code: 500, message: '服务器内部错误', data: null });
  }
});

// 创建帖子接口
app.post('/api/posts/create', checkIdentityVerification, async (req, res) => {
  const { openid, title, content, type, mediaList, contactInfo, location } = req.body;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  
  if (!title || !content) {
    return res.status(400).json({ code: 400, message: '标题和内容不能为空', data: null });
  }
  
  try {
    // 查询用户信息
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    // 将前端类型ID映射到后端类型
    const typeMap = {
      'secondhand': '二手转让',
      'social': '交友',
      'help': '求助',
      'info': '信息分享'
    };
    
    // 创建帖子数据
    const postData = {
      openid,
      title,
      content,
      type: typeMap[type] || '信息分享',
      state: '发布中',
      time: new Date(),
      likeCount: 0,
      commentCount: 0,
      // 添加用户信息，方便前端直接显示
      authorInfo: {
        nickName: user.userInfo?.nickName || '用户',
        avatarUrl: user.userInfo?.avatarUrl || '',
        // 可以添加其他必要的用户信息
      }
    };
    
    // 如果有媒体文件，添加到帖子数据中
    if (mediaList && mediaList.length > 0) {
      // 只保存图片URL
      postData.images = mediaList.filter(media => media.type === 'image').map(media => media.url);
    } else {
      postData.images = [];
    }
    
    // 如果有联系方式，添加到帖子数据中
    if (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo).length > 0) {
      // 确保contactInfo是有效的对象并且有内容
      postData.contactInfo = {
        name: contactInfo.name || '',
        phone: contactInfo.phone || '',
        wechat: contactInfo.wechat || '',
        qq: contactInfo.qq || ''
      };
    } else {
      postData.contactInfo = null;
    }

    // 位置（可选）
    if (location && typeof location === 'object') {
      postData.location = {
        latitude: location.latitude !== undefined ? Number(location.latitude) : undefined,
        longitude: location.longitude !== undefined ? Number(location.longitude) : undefined,
        name: location.name || '',
        address: location.address || ''
      };

      // 若无 name 但有经纬度，则调用腾讯地图逆地理解析填充名称
      const namePlaceholder = !postData.location.name || 
                              postData.location.name.trim() === '' ||
                              ['暂无地址', '未知', 'N/A', '当前位置'].includes(postData.location.name.trim());
      const lat = postData.location.latitude;
      const lng = postData.location.longitude;
      const hasKey = !!TENCENT_MAP_KEY;
      
      console.log(`[逆解析判断] namePlaceholder= ${namePlaceholder}  lat= ${lat}  lng= ${lng}  hasKey= ${hasKey}`);
      
      if (namePlaceholder &&
          lat !== undefined && lng !== undefined &&
          hasKey) {
            console.log('调用腾讯地图逆地理解析获取位置信息...');
        try {
          // 腾讯地图WebService API - 逆地理编码（按官方文档使用签名）
          const pathname = '/ws/geocoder/v1/';
          const params = {
            key: TENCENT_MAP_KEY,
            location: `${postData.location.latitude},${postData.location.longitude}`,
            get_poi: 1,
            coord_type: 5
          };
          
          let url;
          if (TENCENT_MAP_SK) {
            // 有SK则使用签名
            const sig = buildTencentSig(pathname, params, TENCENT_MAP_SK);
            const encodedQuery = buildQueryStringEncoded(params);
            url = `https://apis.map.qq.com${pathname}?${encodedQuery}&sig=${sig}`;
          } else {
            // 无SK则简单拼接
            const encodedQuery = buildQueryStringEncoded(params);
            url = `https://apis.map.qq.com${pathname}?${encodedQuery}`;
          }
          
          console.log('腾讯地图逆地理解析URL:', url);
          const resp = await axios.get(url, { timeout: 5000 });
          if (resp.data && resp.data.status === 0) {
            const result = resp.data.result || {};
            const pois = result.pois || [];
            const poiName = (pois[0] && pois[0].title) || '';
            postData.location.name = poiName || result.formatted_addresses?.recommend || result.address || '当前位置';
            postData.location.address = result.address || postData.location.address;
            console.log('逆地理解析成功，更新位置名称为:', postData.location.name);
          } else {
            console.warn('逆地理解析API返回错误:', resp.data);
          }
        } catch (geoErr) {
          console.warn('逆地理解析失败，不影响发帖:', geoErr?.message || geoErr);
        }
      }
    }
    
    console.log('准备创建帖子:', JSON.stringify(postData, null, 2));
    
    // 保存帖子
    const post = await Post.create(postData);
    
    // 更新用户帖子计数
    await User.findOneAndUpdate(
      { openid },
      { $inc: { postCount: 1 } }
    );
    
    // 记录发帖经验值
    let expResult = null;
    try {
      expResult = await userLevelService.recordExp(openid, 'post');
      console.log(`用户 ${openid} 发帖获得经验: ${expResult.expAdded}`);
    } catch (expError) {
      console.error('记录发帖经验值失败:', expError);
      // 发帖经验记录失败不影响帖子发布
    }
    
    const responseData = {
      id: post._id,
      title: post.title,
      createTime: post.time
    };
    
    // 如果有经验值增加结果，添加到返回数据中
    if (expResult) {
      responseData.expResult = {
        expAdded: expResult.expAdded,
        levelUp: expResult.levelUp,
        levelInfo: expResult.levelInfo
      };
    }
    
    res.json({
      code: 0,
      message: '帖子发布成功',
      data: responseData
    });
  } catch (error) {
    console.error('创建帖子失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 删除帖子
app.post('/api/post/delete', async (req, res) => {
  const { openid, postId } = req.body;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  
  if (!postId) {
    return res.status(400).json({ code: 400, message: '帖子ID不能为空', data: null });
  }
  
  try {
    // 查找帖子确认存在且属于当前用户
    const post = await Post.findOne({ _id: postId });
    
    if (!post) {
      return res.status(404).json({ code: 404, message: '帖子不存在', data: null });
    }
    
    if (post.openid !== openid) {
      return res.status(403).json({ code: 403, message: '无权删除该帖子', data: null });
    }
    
    // 删除帖子相关的媒体文件
    if (post.images && post.images.length > 0) {
      post.images.forEach(imageUrl => {
        try {
          // 从URL中提取用户ID和文件名
          const urlParts = imageUrl.split('/');
          const filename = urlParts.pop(); // 获取最后一部分作为文件名
          const userFolder = urlParts.pop(); // 获取倒数第二部分作为用户文件夹名
          
          if (filename && userFolder) {
            const filePath = path.join(__dirname, '../File/Images/PostImage', userFolder, filename);
            if (fs.existsSync(filePath)) {
              fs.unlinkSync(filePath);
              console.log(`已删除帖子 ${postId} 的媒体文件: ${filename}`);
            }
          }
        } catch (deleteError) {
          console.error('删除帖子媒体文件失败:', deleteError);
          // 继续处理，不影响帖子删除
        }
      });
    }
    
    // 删除帖子
    await Post.deleteOne({ _id: postId });

    // 同时删除该帖子下的所有评论
    await Comment.deleteMany({ postId });

    // 更新用户的帖子计数，防止变成负数
    const user = await User.findOne({ openid });
    if (user && user.postCount > 0) {
      await User.findOneAndUpdate(
        { openid },
        { $inc: { postCount: -1 } }
      );
    } else {
      // 如果postCount已经是0或负数，重新计算正确的数量
      const actualPostCount = await Post.countDocuments({ 
        openid, 
        state: '发布中' 
      });
      await User.findOneAndUpdate(
        { openid },
        { postCount: actualPostCount }
      );
      console.log(`用户 ${openid} 的帖子计数已重新校正为: ${actualPostCount}`);
    }
    
    res.json({
      code: 0,
      message: '删除成功',
      data: null
    });
  } catch (error) {
    console.error('删除帖子失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 超级管理员删除任意帖子
app.post('/api/admin/post/delete', checkSuperAdminPermission, async (req, res) => {
  const { openid, postId } = req.body;
  if (!postId) {
    return res.status(400).json({ code: 400, message: '帖子ID不能为空', data: null });
  }
  try {
    const post = await Post.findById(postId);
    if (!post) return res.status(404).json({ code: 404, message: '帖子不存在', data: null });

    // 删除帖子相关媒体（与普通删除相同逻辑）
    if (post.images && post.images.length > 0) {
      post.images.forEach(imageUrl => {
        try {
          const urlParts = imageUrl.split('/');
          const filename = urlParts.pop();
          const userFolder = urlParts.pop();
          if (filename && userFolder) {
            const filePath = path.join(__dirname, '../File/Images/PostImage', userFolder, filename);
            if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
          }
        } catch (_) {}
      });
    }

    await Comment.deleteMany({ postId: postId });
    await Post.deleteOne({ _id: postId });
    await User.findOneAndUpdate({ openid: post.openid }, { $inc: { postCount: -1 } });
    return res.json({ code: 0, message: '删除成功', data: null });
  } catch (err) {
    console.error('管理员删除帖子失败:', err);
    return res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 获取帖子列表接口
app.get('/api/posts/list', async (req, res) => {
  const { page = 1, pageSize = 10, openid } = req.query;
  
  // 将页码和每页数量转换为数字
  const pageNum = parseInt(page);
  const limit = parseInt(pageSize);
  const skip = (pageNum - 1) * limit;
  
  console.log(`获取帖子列表请求: page=${pageNum}, pageSize=${limit}, openid=${openid || '未提供'}`);
  
  try {
    // 查询帖子总数（包含发布中与已结束）
    const total = await Post.countDocuments({});
    
    // 查询帖子列表，按时间倒序排序（包含所有状态）
    const posts = await Post.find({})
      .sort({ time: -1 }) // 按发布时间倒序排序
      .skip(skip)
      .limit(limit)
      .exec();
    
    console.log(`查询到 ${posts.length} 条帖子`);
    
    // 获取帖子ID列表
    const postIds = posts.map(post => post._id);
    
    // 收集所有帖子作者的openid
    const authorOpenids = [...new Set(posts.map(post => post.openid))];
    
    // 查询所有作者的最新信息
    const authors = await User.find({ openid: { $in: authorOpenids } });
    
    // 创建作者信息映射，以openid为键
    const authorInfoMap = {};
    authors.forEach(author => {
      authorInfoMap[author.openid] = {
        nickName: author.userInfo?.nickName || '用户',
        avatarUrl: author.userInfo?.avatarUrl || ''
      };
    });
    
    // 如果提供了openid，从帖子的likedBy数组中检查点赞状态
    let likeStatusMap = {};
    if (openid) {
      // 直接从帖子数据中构建点赞状态映射
      likeStatusMap = posts.reduce((map, post) => {
        const postIdStr = post._id.toString();
        const isLiked = post.likedBy && post.likedBy.includes(openid);
        if (isLiked) {
          map[postIdStr] = true;
        }
        return map;
      }, {});
      
      const likedPostsCount = Object.keys(likeStatusMap).length;
      console.log(`用户 ${openid} 对查询的帖子有 ${likedPostsCount} 个点赞记录`);
    }
    
    // 格式化返回数据，适配前端期望的格式
    const formattedPosts = posts.map(post => {
      // 构建媒体列表
      const mediaList = post.images ? post.images.map(url => ({
        type: "image",
        url: url
      })) : [];
      
      // 检查用户是否点赞过该帖子
      const postIdStr = post._id.toString();
      const isLiked = openid ? !!likeStatusMap[postIdStr] : false;
      
      if (openid && likeStatusMap[postIdStr]) {
        console.log(`帖子 ${postIdStr} 被用户 ${openid} 点赞过`);
      }
      
      // 使用最新的作者信息，如果找不到则使用帖子中存储的信息
      const latestAuthorInfo = authorInfoMap[post.openid] || post.authorInfo || {
        nickName: '用户',
        avatarUrl: ''
      };
      
      return {
        id: post._id,
        title: post.title,
        content: post.content,
        createTime: post.time, // 使用time字段作为createTime返回
        likes: post.likeCount || 0,
        comments: post.commentCount || 0,
        userInfo: latestAuthorInfo,
        mediaList: mediaList,
        type: post.type,
        status: post.state === '发布中' ? 'active' : 'ended',
        isLiked: isLiked
      };
    });
    
    res.json({
      code: 0,
      message: 'success',
      data: formattedPosts
    });
  } catch (error) {
    console.error('获取帖子列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 配置轮播图访问路径
app.use('/File/Images/Banners', express.static(path.join(__dirname, '../File/Images/Banners')));

// 获取轮播图列表接口
app.get('/api/banners/list', async (req, res) => {
  try {
    const bannerDir = path.join(__dirname, '../File/Images/Banners');
    
    // 确保目录存在
    if (!fs.existsSync(bannerDir)) {
      fs.mkdirSync(bannerDir, { recursive: true });
      console.log('创建轮播图目录:', bannerDir);
    }
    
    // 读取目录中的所有文件
    fs.readdir(bannerDir, (err, files) => {
      if (err) {
        console.error('读取轮播图目录失败:', err);
        return res.status(500).json({ code: 500, message: '服务器错误', data: null });
      }
      
      // 过滤出图片文件（简单判断扩展名）
      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
      const imageFiles = files.filter(file => {
        const ext = path.extname(file).toLowerCase();
        return imageExtensions.includes(ext);
      });
      
      // 生成完整的图片URL - 修复协议和域名问题
      const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
      const host = req.get('x-forwarded-host') || req.get('host');
      const bannerUrls = imageFiles.map(file => {
        return `${protocol}://${host}/File/Images/Banners/${file}`;
      });
      
      // 如果没有找到图片，返回空数组
      if (bannerUrls.length === 0) {
        console.log('轮播图目录中没有找到图片');
      } else {
        console.log('找到轮播图:', bannerUrls);
      }
      
      res.json({
        code: 0,
        message: 'success',
        data: bannerUrls
      });
    });
  } catch (error) {
    console.error('获取轮播图列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 配置轮播图上传
const bannerStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const bannerDir = path.join(__dirname, '../File/Images/Banners');
    // 确保目录存在
    if (!fs.existsSync(bannerDir)) {
      fs.mkdirSync(bannerDir, { recursive: true });
    }
    cb(null, bannerDir);
  },
  filename: function (req, file, cb) {
    // 生成唯一文件名，保留原始扩展名
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    let ext = path.extname(file.originalname).toLowerCase();
    
    // 如果没有扩展名，根据mimetype补充
    if (!ext) {
      if (file.mimetype === 'image/jpeg') ext = '.jpg';
      else if (file.mimetype === 'image/png') ext = '.png';
      else if (file.mimetype === 'image/gif') ext = '.gif';
      else if (file.mimetype === 'image/webp') ext = '.webp';
      else ext = '.jpg'; // 默认扩展名
    }
    
    console.log('上传轮播图文件信息:', {
      originalName: file.originalname,
      mimetype: file.mimetype,
      detectedExtension: ext,
      newFilename: `banner-${uniqueSuffix}${ext}`
    });
    
    cb(null, `banner-${uniqueSuffix}${ext}`);
  }
});

const uploadBanner = multer({ 
  storage: bannerStorage,
  limits: {
    fileSize: 10 * 1024 * 1024, // 限制10MB
  },
  fileFilter: function (req, file, cb) {
    // 只允许图片格式
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('只允许上传图片文件!'), false);
    }
  }
});

// 配置身份证照片上传
const identityStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const { openid } = req.body;
    // 为每个用户创建单独的身份验证文件夹
    const uploadDir = path.join(__dirname, '../File/Identify', openid || 'anonymous');
    
    // 确保目录存在
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    cb(null, uploadDir);
  },
  filename: function (req, file, cb) {
    const { type } = req.body; // id_front 或 id_back
    
    // 确保获取正确的原始扩展名
    let ext = path.extname(file.originalname).toLowerCase();
    
    // 如果没有扩展名，根据mimetype补充
    if (!ext) {
      if (file.mimetype === 'image/jpeg') ext = '.jpg';
      else if (file.mimetype === 'image/png') ext = '.png';
      else if (file.mimetype === 'image/gif') ext = '.gif';
      else if (file.mimetype === 'image/webp') ext = '.webp';
      else ext = '.jpg'; // 默认扩展名
    }
    
    // 使用固定的文件名：front 或 back
    const filename = type === 'id_back' ? `back${ext}` : `front${ext}`;
    
    console.log('上传身份证照片信息:', {
      originalName: file.originalname,
      mimetype: file.mimetype,
      type: type,
      detectedExtension: ext,
      newFilename: filename
    });
    
    cb(null, filename);
  }
});

const uploadIdentity = multer({ 
  storage: identityStorage,
  limits: {
    fileSize: 10 * 1024 * 1024, // 限制10MB
  },
  fileFilter: function (req, file, cb) {
    // 只允许图片格式
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('只允许上传图片文件!'), false);
    }
  }
});

// 上传轮播图接口
app.post('/api/banners/upload', uploadBanner.single('banner'), checkAdminPermission, async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ 
        code: 400, 
        message: '请选择要上传的轮播图', 
        data: null 
      });
    }
    
    // 记录保存文件的详细信息
    console.log('保存轮播图文件信息:', {
      filename: req.file.filename,
      originalname: req.file.originalname,
      mimetype: req.file.mimetype,
      destination: req.file.destination,
      path: req.file.path,
      size: req.file.size
    });
    
    // 生成可访问的URL
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const bannerUrl = `${protocol}://${host}/File/Images/Banners/${req.file.filename}`;
    console.log('生成的轮播图URL:', bannerUrl);
    
    res.json({
      code: 0,
      message: '轮播图上传成功',
      data: {
        url: bannerUrl,
        filename: req.file.filename
      }
    });
  } catch (error) {
    console.error('上传轮播图失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '上传轮播图失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 删除轮播图接口
app.post('/api/banners/delete', checkAdminPermission, async (req, res) => {
  try {
    const { filename } = req.body;
    
    if (!filename) {
      return res.status(400).json({ 
        code: 400, 
        message: '文件名不能为空', 
        data: null 
      });
    }
    
    const bannerPath = path.join(__dirname, '../File/Images/Banners', filename);
    
    // 检查文件是否存在
    if (!fs.existsSync(bannerPath)) {
      return res.status(404).json({ 
        code: 404, 
        message: '轮播图文件不存在', 
        data: null 
      });
    }
    
    // 删除文件
    fs.unlinkSync(bannerPath);
    console.log('删除轮播图文件:', bannerPath);
    
    res.json({
      code: 0,
      message: '轮播图删除成功',
      data: null
    });
  } catch (error) {
    console.error('删除轮播图失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '删除轮播图失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// ===================== 配置管理相关接口 =====================

// ===================== 广播设置相关接口 =====================

// 获取广播配置接口
app.get('/api/broadcast/config', async (req, res) => {
  try {
    const config = await Config.findOne({ type: 'system', key: 'broadcast' });
    
    const defaultConfig = {
      content: '',
      style: 'scroll',
      enabled: false,
      speed: 20,
      background: 'orange'
    };
    
    res.json({
      code: 0,
      message: 'success',
      data: config ? config.value : defaultConfig
    });
  } catch (error) {
    console.error('获取广播配置失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '获取广播配置失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 保存广播配置接口
app.post('/api/broadcast/config', checkAdminPermission, async (req, res) => {
  try {
    const { content, style, enabled, speed, background } = req.body;
    const openid = req.body.openid;
    
    // 验证参数
    if (style && !['scroll', 'static'].includes(style)) {
      return res.status(400).json({ 
        code: 400, 
        message: '无效的广播样式', 
        data: null 
      });
    }

    if (background && !['orange', 'blue', 'green', 'purple'].includes(background)) {
      return res.status(400).json({ 
        code: 400, 
        message: '无效的背景颜色', 
        data: null 
      });
    }

    if (speed && (speed < 5 || speed > 60)) {
      return res.status(400).json({ 
        code: 400, 
        message: '滚动速度必须在5-60秒之间', 
        data: null 
      });
    }
    
    const broadcastConfig = {
      content: content || '',
      style: style || 'scroll',
      enabled: enabled === true,
      speed: speed || 20,
      background: background || 'orange'
    };
    
    // 使用upsert更新或创建广播配置
    const config = await Config.findOneAndUpdate(
      { type: 'system', key: 'broadcast' },
      {
        type: 'system',
        key: 'broadcast',
        value: broadcastConfig,
        description: '首页广播配置',
        updatedAt: new Date(),
        updatedBy: openid
      },
      {
        upsert: true,
        new: true,
        setDefaultsOnInsert: true
      }
    );

    // 如果是新创建的配置，设置创建者
    if (!config.createdBy) {
      config.createdBy = openid;
      await config.save();
    }
    
    res.json({
      code: 0,
      message: '广播配置保存成功',
      data: config.value
    });
  } catch (error) {
    console.error('保存广播配置失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '保存广播配置失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// ===================== 通用配置管理接口 =====================

// 获取配置接口
app.get('/api/config/:type', async (req, res) => {
  try {
    const { type } = req.params;
    const { key } = req.query;
    
    // 验证配置类型
    const validTypes = ['customerService', 'cooperation', 'banner', 'system'];
    if (!validTypes.includes(type)) {
      return res.status(400).json({ 
        code: 400, 
        message: '无效的配置类型', 
        data: null 
      });
    }

    let query = { type, enabled: true };
    if (key) {
      query.key = key;
    }

    const configs = await Config.find(query).sort({ createdAt: -1 });
    
    // 如果指定了key，返回单个配置的value
    if (key) {
      const config = configs[0];
      return res.json({
        code: 0,
        message: 'success',
        data: config ? config.value : null
      });
    }
    
    // 否则返回所有配置
    const result = {};
    configs.forEach(config => {
      result[config.key] = config.value;
    });
    
    res.json({
      code: 0,
      message: 'success',
      data: result
    });
  } catch (error) {
    console.error('获取配置失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '获取配置失败', 
      data: null 
    });
  }
});

// 保存配置接口
app.post('/api/config/:type', checkAdminPermission, async (req, res) => {
  try {
    const { type } = req.params;
    const { key, value, description } = req.body;
    const openid = req.body.openid;
    
    // 验证参数
    if (!key || value === undefined) {
      return res.status(400).json({ 
        code: 400, 
        message: 'key和value不能为空', 
        data: null 
      });
    }
    
    // 验证配置类型
    const validTypes = ['customerService', 'cooperation', 'banner', 'system'];
    if (!validTypes.includes(type)) {
      return res.status(400).json({ 
        code: 400, 
        message: '无效的配置类型', 
        data: null 
      });
    }

    // 使用upsert更新或创建配置
    const config = await Config.findOneAndUpdate(
      { type, key },
      {
        type,
        key,
        value,
        description: description || '',
        updatedAt: new Date(),
        updatedBy: openid
      },
      {
        upsert: true,
        new: true,
        setDefaultsOnInsert: true
      }
    );

    // 如果是新创建的配置，设置创建者
    if (!config.createdBy) {
      config.createdBy = openid;
      await config.save();
    }
    
    res.json({
      code: 0,
      message: '配置保存成功',
      data: config
    });
  } catch (error) {
    console.error('保存配置失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '保存配置失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 删除配置接口
app.delete('/api/config/:type/:key', checkAdminPermission, async (req, res) => {
  try {
    const { type, key } = req.params;
    
    // 验证配置类型
    const validTypes = ['customerService', 'cooperation', 'banner', 'system'];
    if (!validTypes.includes(type)) {
      return res.status(400).json({ 
        code: 400, 
        message: '无效的配置类型', 
        data: null 
      });
    }

    const result = await Config.findOneAndDelete({ type, key });
    
    if (!result) {
      return res.status(404).json({ 
        code: 404, 
        message: '配置不存在', 
        data: null 
      });
    }
    
    res.json({
      code: 0,
      message: '配置删除成功',
      data: null
    });
  } catch (error) {
    console.error('删除配置失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '删除配置失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 帖子点赞/取消点赞统一接口
app.post('/api/posts/like', checkIdentityVerification, async (req, res) => {
  const { postId, openid, action } = req.body; // action: 'like' or 'unlike'

  if (!postId || !openid || !action) {
    return res.status(400).json({ code: 400, message: 'postId, openid 和 action 不能为空', data: null });
  }

  try {
    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ code: 404, message: '帖子不存在', data: null });
    }
    // 已结束的帖子不可点赞
    if (post.state !== '发布中') {
      return res.json({ code: 0, message: '已结束的帖子不可点赞', data: { likes: post.likeCount || 0, isLiked: post.likedBy?.includes(openid) || false } });
    }

    let update;
    let message;
    let isLiked;

    if (action === 'like') {
      // 使用 $addToSet 保证 openid 的唯一性
      update = { 
        $addToSet: { likedBy: openid },
        $inc: { likeCount: 1 } 
      };
      message = '点赞成功';
      isLiked = true;

      // 防止重复增加 likeCount
      if (post.likedBy.includes(openid)) {
        update.$inc.likeCount = 0; // 如果已经点赞，则不增加数量
        message = '已经点过赞了';
      }

    } else if (action === 'unlike') {
      // 使用 $pull 从数组中移除 openid
      update = { 
        $pull: { likedBy: openid },
        $inc: { likeCount: -1 }
      };
      message = '取消点赞成功';
      isLiked = false;

      // 防止重复减少 likeCount
      if (!post.likedBy.includes(openid)) {
        update.$inc.likeCount = 0; // 如果未点赞，则不减少数量
        message = '您还没有点赞';
      }
    } else {
      return res.status(400).json({ code: 400, message: '无效的 action 参数', data: null });
    }

    const updatedPost = await Post.findByIdAndUpdate(postId, update, { new: true });
    
    // 经验值与消息通知逻辑
    // 需求：同一用户对同一帖子只在"第一次点赞"时通知；取消点赞后再次点赞不再通知
    // 实现：查询是否已存在该组合的点赞消息记录，存在则不再创建
    try {
      if (action === 'like') {
        if (post.openid === openid) {
          console.log('跳过消息创建: 用户给自己的帖子点赞');
        } else {
          const existingLikeMsg = await Message.findOne({
            type: 1,
            senderId: openid,
            receiverId: post.openid,
            postId: post._id
          });

          const shouldNotify = !existingLikeMsg; // 仅首次点赞
          if (shouldNotify) {
            await userLevelService.recordExp(openid, 'like');
            await userLevelService.recordExp(post.openid, 'beingLiked');
            const liker = await User.findOne({ openid });

            await Message.create({
              type: 1,
              senderId: openid,
              senderNickName: liker?.userInfo?.nickName || '用户',
              senderAvatar: liker?.userInfo?.avatarUrl || '',
              receiverId: post.openid,
              postId: post._id,
              postTitle: post.title || (post.content ? post.content.substring(0, 20) : '帖子')
            });
            console.log(`✅ 首次点赞消息已创建: ${openid} -> 帖子 ${post._id}`);
          } else {
            console.log('跳过消息创建: 已存在该用户对此帖的点赞消息记录');
          }
        }
      }
    } catch (error) {
      console.error('处理点赞后逻辑失败:', error);
    }

    res.json({
      code: 0,
      message,
      data: {
        likes: updatedPost.likeCount,
        isLiked,
      },
    });

  } catch (error) {
    console.error('处理点赞操作失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 获取用户对帖子的点赞状态
app.get('/api/posts/like/status', async (req, res) => {
  const { postIds, openid } = req.query;
  
  if (!postIds || !openid) {
    return res.status(400).json({ code: 400, message: 'postIds和openid不能为空', data: null });
  }
  
  try {
    // 将逗号分隔的帖子ID转换为数组
    const postIdArray = postIds.split(',');
    
    // 查询这些帖子，检查likedBy数组
    const posts = await Post.find({
      _id: { $in: postIdArray }
    });
    
    // 构建点赞状态映射
    const likeStatus = {};
    postIdArray.forEach(id => {
      likeStatus[id] = false;
    });
    
    // 检查用户是否在每个帖子的likedBy数组中
    posts.forEach(post => {
      const postIdStr = post._id.toString();
      if (post.likedBy && post.likedBy.includes(openid)) {
        likeStatus[postIdStr] = true;
      }
    });
    
    res.json({
      code: 0,
      message: 'success',
      data: likeStatus
    });
  } catch (error) {
    console.error('获取点赞状态失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 记录经验值接口
app.post('/api/user/recordExp', async (req, res) => {
  const { openid, type, value } = req.body;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  
  if (!type) {
    return res.status(400).json({ code: 400, message: '经验值类型不能为空', data: null });
  }
  
  try {
    // 记录经验值
    const result = await userLevelService.recordExp(openid, type, value ? parseInt(value) : null);
    
    res.json({
      code: 0,
      message: result.limitReached ? '已达到每日上限' : 'success',
      data: {
        expAdded: result.expAdded,
        expInfo: result.expInfo,
        levelInfo: result.levelInfo,
        levelUp: result.levelUp
      }
    });
  } catch (error) {
    console.error('记录经验值失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '记录经验值失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 新版评论接口，支持回复功能
app.post('/api/posts/comment/add', checkIdentityVerification, async (req, res) => {
  const { openid, postId, content, replyCommentId, replyToCommentId, replyToOpenid } = req.body;
  
  // 添加调试日志
  console.log('评论请求参数:', { openid, postId, content, replyCommentId, replyToCommentId, replyToOpenid });
  
  if (!openid || !postId || !content) {
    return res.status(400).json({ code: 400, message: '参数不完整', data: null });
  }
  
  try {
    // 检查帖子是否存在
    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ code: 404, message: '帖子不存在', data: null });
    }
    // 已结束的帖子不可评论
    if (post.state !== '发布中') {
      return res.status(400).json({ code: 400, message: '已结束的帖子不可评论', data: null });
    }
    
    // 查询评论者信息
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    // 准备评论数据
    const commentData = {
      postId,
      openid,
      content,
      time: new Date(),
      // 添加用户信息，方便前端直接显示
      authorInfo: {
        nickName: user.userInfo?.nickName || '用户',
        avatarUrl: user.userInfo?.avatarUrl || ''
      }
    };
    
    // 如果是回复评论
    if (replyCommentId) {
      // 查询被回复的评论
      const parentComment = await Comment.findById(replyCommentId);
      if (!parentComment) {
        return res.status(404).json({ code: 404, message: '被回复的评论不存在', data: null });
      }
      
      // 设置父评论ID和被回复评论ID
      commentData.parentId = replyCommentId;
      // 如果有明确的被回复评论ID，使用它；否则使用父评论ID
      commentData.replyTo = replyToCommentId || replyCommentId;
      
      // 如果父评论有根评论ID，则继承
      if (parentComment.rootCommentId) {
        commentData.rootCommentId = parentComment.rootCommentId;
        commentData.depth = parentComment.depth + 1;
      } else {
        // 父评论就是根评论
        commentData.rootCommentId = replyCommentId;
        commentData.depth = 2; // 回复层级为2
      }
    }
    
    // 创建评论
    const comment = await Comment.create(commentData);
    
    // 更新帖子评论数
    post.commentCount = (post.commentCount || 0) + 1;
    await post.save();
    
    console.log(`用户 ${openid} 评论成功，帖子 ${postId} 当前评论数: ${post.commentCount}`);
    
    // 记录评论者的经验值
    let commenterExpResult = null;
    try {
      commenterExpResult = await userLevelService.recordExp(openid, 'comment');
      console.log(`用户 ${openid} 评论获得经验: ${commenterExpResult.expAdded}`);
    } catch (expError) {
      console.error('记录评论经验值失败:', expError);
      // 经验记录失败不影响评论操作
    }
    
    // 通知机制优化：避免对同一一级评论同时触发两种通知
    if (replyCommentId) {
      // 如果是回复评论，仅发送"回复了您的评论"通知
      const parentComment = await Comment.findById(replyCommentId);
      if (parentComment) {
        // 确定通知接收者：如果有replyToOpenid则通知被回复用户，否则通知父评论作者
        const receiverId = replyToOpenid && replyToOpenid !== openid ? replyToOpenid : parentComment.openid;
        
        console.log('通知逻辑调试:', {
          replyToOpenid,
          parentCommentOpenid: parentComment.openid,
          currentUserOpenid: openid,
          finalReceiverId: receiverId,
          shouldCreateNotification: receiverId !== openid
        });
        
        // 只有当接收者不是当前用户时才创建通知
        if (receiverId !== openid) {
          // 给被回复者经验奖励
          try {
            const commentAuthorExpResult = await userLevelService.recordExp(receiverId, 'beingCommented');
            console.log(`被回复用户 ${receiverId} 获得经验: ${commentAuthorExpResult.expAdded}`);
          } catch (expError) {
            console.error('记录被回复经验值失败:', expError);
          }
          
          // 创建回复消息通知
          try {
            const message = new Message({
              type: 3, // 回复评论
              senderId: openid,
              senderNickName: user.userInfo?.nickName || '用户',
              senderAvatar: user.userInfo?.avatarUrl || '',
              receiverId: receiverId,
              postId: post._id,
              postTitle: post.title || (post.content ? post.content.substring(0, 20) : '帖子'),
              commentId: parentComment._id,
              replyId: comment._id,
              content: content ? content.substring(0, 50) : '', // 评论内容截取前50个字符
              isRead: false,
              createTime: Date.now()
            });
            
            await message.save();
            console.log(`创建回复消息通知成功: 用户 ${openid} 回复了用户 ${receiverId}`);
          } catch (msgError) {
            console.error('创建回复消息通知失败:', msgError);
            // 消息创建失败不影响评论操作
          }
        } else {
          console.log('不创建通知：用户回复了自己的评论');
        }
      }
    } else {
      // 如果是一级评论，仅发送"评论了您的帖子"通知
      if (post.openid !== openid) {
        try {
          const authorExpResult = await userLevelService.recordExp(post.openid, 'beingCommented');
          console.log(`帖子作者 ${post.openid} 被评论获得经验: ${authorExpResult.expAdded}`);
        } catch (expError) {
          console.error('记录被评论经验值失败:', expError);
        }
        
        // 创建评论消息通知（给帖子作者）
        try {
          const message = new Message({
            type: 2, // 评论帖子
            senderId: openid,
            senderNickName: user.userInfo?.nickName || '用户',
            senderAvatar: user.userInfo?.avatarUrl || '',
            receiverId: post.openid, 
            postId: post._id,
            postTitle: post.title || (post.content ? post.content.substring(0, 20) : '帖子'),
            commentId: comment._id,
            content: content ? content.substring(0, 50) : '', // 评论内容截取前50个字符
            isRead: false,
            createTime: Date.now()
          });
          
          await message.save();
          console.log(`创建评论消息通知成功: 用户 ${openid} 评论了帖子 ${postId}`);
        } catch (msgError) {
          console.error('创建评论消息通知失败:', msgError);
          // 消息创建失败不影响评论操作
        }
      }
    }
    
    const responseData = {
      id: comment._id,
      content: comment.content,
      createTime: comment.time,
      authorInfo: comment.authorInfo
    };
    
    // 如果有经验值增加结果，添加到返回数据中
    if (commenterExpResult) {
      responseData.expResult = {
        expAdded: commenterExpResult.expAdded,
        levelUp: commenterExpResult.levelUp,
        levelInfo: commenterExpResult.levelInfo
      };
    }
    
    res.json({
      code: 0,
      message: '评论成功',
      data: responseData
    });
  } catch (error) {
    console.error('添加评论失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 记录分享接口
app.post('/api/share/record', async (req, res) => {
  const { openid, postId } = req.body;
  
  if (!openid) {
    return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
  }
  
  try {
    // 记录分享经验
    const result = await userLevelService.recordExp(openid, 'share');
    
    // 如果提供了帖子ID，给帖子作者增加被分享经验
    if (postId) {
      try {
        const post = await Post.findById(postId);
        if (post && post.openid !== openid) { // 不给自己分享加经验
          await userLevelService.recordExp(post.openid, 'beingShared');
        }
      } catch (error) {
        console.error('记录帖子被分享经验失败:', error);
        // 这个错误不影响主流程
      }
    }
    
    res.json({
      code: 0,
      message: result.limitReached ? '已达到每日上限' : 'success',
      data: {
        expAdded: result.expAdded,
        levelUp: result.levelUp,
        levelInfo: result.levelInfo
      }
    });
  } catch (error) {
    console.error('记录分享经验失败:', error);
    res.status(500).json({ 
      code: 500, 
      message: '记录分享经验失败: ' + (error.message || '服务器错误'), 
      data: null 
    });
  }
});

// 获取帖子详情接口
app.get('/api/posts/detail', async (req, res) => {
  const { postId, openid } = req.query;
  
  if (!postId) {
    return res.status(400).json({ code: 400, message: 'postId不能为空', data: null });
  }
  
  try {
    // 查询帖子
    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ code: 2001, message: '帖子不存在', data: null });
    }
    
    // 检查用户是否点赞过该帖子
    let isLiked = false;
    if (openid && post.likedBy) {
      isLiked = post.likedBy.includes(openid);
    }
    
    // 获取作者信息
    const author = await User.findOne({ openid: post.openid });
    const authorInfo = post.authorInfo || {
      nickName: author?.userInfo?.nickName || '用户',
      avatarUrl: author?.userInfo?.avatarUrl || ''
    };
    
    // 获取作者等级信息
    const level = author?.expInfo?.level || 1;
    const levelName = author?.expInfo?.levelName || '见习观察者';
    
    // 格式化返回数据
    const formattedPost = {
      id: post._id,
      userId: post.openid,
      openid: post.openid, // 增加openid字段
      avatarUrl: authorInfo.avatarUrl,
      nickName: authorInfo.nickName,
      level: level,  // 添加等级
      levelName: levelName, // 添加等级名称
      levelIcon: `/images/level-${level}.png`, // 添加等级图标
      time: post.time,
      title: post.title,
      content: post.content,
      images: post.images || [],
      tags: post.tags || [], // 返回标签
      location: post.location || null,
      likes: post.likeCount || 0,
      comments: post.commentCount || 0,
      shares: post.shareCount || 0, // 添加分享数
      isLiked: isLiked,
      type: post.type,
      status: post.state === '发布中' ? 'active' : 'ended',
      contactInfo: post.contactInfo || null
    };
    
    res.json({
      code: 0,
      message: 'success',
      data: formattedPost
    });
  } catch (error) {
    console.error('获取帖子详情失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 获取帖子评论列表接口
app.get('/api/posts/comments', async (req, res) => {
  const { postId, openid, page = 1, size = 10 } = req.query;
  
  if (!postId) {
    return res.status(400).json({ code: 400, message: 'postId不能为空', data: null });
  }
  
  try {
    // 计算分页
    const skip = (parseInt(page) - 1) * parseInt(size);
    const limit = parseInt(size);
    
    // 查询一级评论总数（只统计没有parentId的评论）
    const total = await Comment.countDocuments({ 
      postId, 
      $or: [
        { parentId: { $exists: false } },
        { parentId: null }
      ]
    });
    
    // 查询一级评论（只查询没有parentId的评论）
    const comments = await Comment.find({ 
      postId,
      $or: [
        { parentId: { $exists: false } },
        { parentId: null }
      ]
    })
      .sort({ time: -1 }) // 按时间倒序排序
      .skip(skip)
      .limit(limit)
      .exec();
    
    // 格式化评论数据
    const formattedComments = await Promise.all(comments.map(async (comment) => {
      // 检查用户是否点赞过该评论（使用新的likedBy数组）
      const isLiked = openid && comment.likedBy ? comment.likedBy.includes(openid) : false;
      
      // 获取评论者用户信息和等级
      const commentAuthor = await User.findOne({ openid: comment.openid }).lean();
      const authorInfo = comment.authorInfo || {};
      const level = commentAuthor?.expInfo?.level || 1;
      const levelName = commentAuthor?.expInfo?.levelName || '见习观察者';
      
      // 查询回复（子评论）
      const replies = await Comment.find({ 
        parentId: comment._id 
      }).sort({ time: 1 }).exec();
      
      // 格式化回复数据
      const formattedReplies = await Promise.all(replies.map(async (reply) => {
        // 获取回复者信息和等级
        const replyAuthor = await User.findOne({ openid: reply.openid }).lean();
        const replyAuthorInfo = reply.authorInfo || {};
        const replyLevel = replyAuthor?.expInfo?.level || 1;
        const replyLevelName = replyAuthor?.expInfo?.levelName || '见习观察者';
        
        // 获取被回复者信息和等级
        let replyToNickname = '';
        let replyToUserId = '';
        let replyToLevel = 1;
        let replyToLevelName = '见习观察者';
        
        if (reply.replyTo) {
          const replyToComment = await Comment.findById(reply.replyTo);
          if (replyToComment) {
            replyToUserId = replyToComment.openid;
            
            const replyToAuthorInfo = replyToComment.authorInfo || {};
            replyToNickname = replyToAuthorInfo.nickName || '用户';
            
            // 获取被回复者等级
            const replyToUser = await User.findOne({ openid: replyToComment.openid }).lean();
            if (replyToUser && replyToUser.expInfo) {
              replyToLevel = replyToUser.expInfo.level;
              replyToLevelName = replyToUser.expInfo.levelName;
            }
          }
        }
        
        return {
          id: reply._id,
          postId: reply.postId,
          parentId: reply.parentId,
          userId: reply.openid,
          openid: reply.openid,
          nickName: replyAuthorInfo.nickName || '用户',
          avatarUrl: replyAuthorInfo.avatarUrl || '',
          level: replyLevel,
          levelName: replyLevelName,
          levelIcon: `/images/level-${replyLevel}.png`,
          content: reply.content,
          time: reply.time,
          replyTo: replyToNickname || undefined,
          replyToUserId: replyToUserId || undefined,
          replyToLevel: replyToLevel,
          replyToLevelName: replyToLevelName,
          replyToLevelIcon: `/images/level-${replyToLevel}.png`
        };
      }));
      
      return {
        id: comment._id,
        postId: comment.postId,
        userId: comment.openid,
        openid: comment.openid,
        avatarUrl: authorInfo.avatarUrl || '',
        nickName: authorInfo.nickName || '用户',
        level: level,
        levelName: levelName,
        levelIcon: `/images/level-${level}.png`,
        time: comment.time,
        content: comment.content,
        likes: comment.likeCount || 0,
        likeCount: comment.likeCount || 0, // 同时返回likeCount字段
        isLiked: isLiked,
        replies: formattedReplies
      };
    }));
    
    // 是否有更多评论
    const hasMore = skip + formattedComments.length < total;
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        list: formattedComments,
        total: total,
        page: parseInt(page),
        size: parseInt(size),
        hasMore: hasMore
      }
    });
  } catch (error) {
    console.error('获取评论列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 评论点赞/取消点赞统一接口 (已更新为新的嵌入式系统)
app.post('/api/posts/comment/like', checkIdentityVerification, async (req, res) => {
  const { commentId, openid, action } = req.body; // action: 'like' or 'unlike'
  
  if (!commentId || !openid || !action) {
    return res.status(400).json({ code: 400, message: 'commentId, openid 和 action 不能为空', data: null });
  }
  
  try {
    // 查询评论是否存在
    const comment = await Comment.findById(commentId);
    if (!comment) {
      return res.status(404).json({ code: 2002, message: '评论不存在', data: null });
    }
    
    let update;
    let message;
    let isLiked;
    
    if (action === 'like') {
      // 使用 $addToSet 保证 openid 的唯一性
      update = {
        $addToSet: { likedBy: openid },
        $inc: { likeCount: 1 }
      };
      message = '点赞成功';
      isLiked = true;
      
      // 防止重复增加 likeCount
      if (comment.likedBy && comment.likedBy.includes(openid)) {
        update.$inc.likeCount = 0; // 如果已经点赞，则不增加数量
        message = '已经点过赞了';
      }
      
    } else if (action === 'unlike') {
      // 使用 $pull 从数组中移除 openid
      update = {
        $pull: { likedBy: openid },
        $inc: { likeCount: -1 }
      };
      message = '取消点赞成功';
      isLiked = false;
      
      // 防止重复减少 likeCount
      if (!comment.likedBy || !comment.likedBy.includes(openid)) {
        update.$inc.likeCount = 0; // 如果未点赞，则不减少数量
        message = '您还没有点赞';
      }
    } else {
      return res.status(400).json({ code: 400, message: '无效的 action 参数', data: null });
    }
    
    const updatedComment = await Comment.findByIdAndUpdate(commentId, update, { new: true });
    
    // 经验值和消息通知逻辑 (仅在成功点赞时触发)
    if (action === 'like' && comment.openid !== openid && (!comment.likedBy || !comment.likedBy.includes(openid))) {
      try {
        await userLevelService.recordExp(comment.openid, 'beingLiked');
      } catch (expError) {
        console.error('记录评论被点赞经验值失败:', expError);
      }
      
      // 创建评论点赞消息通知
      try {
        // 获取点赞用户信息
        const liker = await User.findOne({ openid });
        const likerInfo = liker?.userInfo || {};
        
        // 查询帖子信息
        const post = await Post.findById(comment.postId);
        const postTitle = post ? (post.title || (post.content ? post.content.substring(0, 20) : '帖子')) : '帖子';
        
        // 创建点赞消息
        const messageDoc = new Message({
          type: 4, // 评论被点赞
          senderId: openid,
          senderNickName: likerInfo.nickName || '用户',
          senderAvatar: likerInfo.avatarUrl || '',
          receiverId: comment.openid,
          postId: comment.postId,
          postTitle: postTitle,
          commentId: comment._id,
          content: comment.content ? comment.content.substring(0, 50) : '', // 评论内容摘要
          isRead: false,
          createTime: Date.now()
        });
        
        await messageDoc.save();
        console.log(`创建评论点赞消息通知成功: 用户 ${openid} 点赞了评论 ${commentId}`);
      } catch (msgError) {
        console.error('创建评论点赞消息通知失败:', msgError);
        // 消息创建失败不影响点赞操作
      }
    }
    
    res.json({
      code: 0,
      message,
      data: {
        likes: updatedComment.likeCount,
        isLiked
      }
    });
  } catch (error) {
    console.error('处理评论点赞操作失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 评论接口（旧版本，保留兼容）
app.post('/api/comments/add', checkIdentityVerification, async (req, res) => {
  const { openid, postId, content } = req.body;
  
  if (!openid || !postId || !content) {
    return res.status(400).json({ code: 400, message: '参数不完整', data: null });
  }
  
  try {
    // 检查帖子是否存在
    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ code: 404, message: '帖子不存在', data: null });
    }
    
    // 查询评论者信息
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    // 创建评论
    const commentData = {
      postId,
      openid,
      content,
      time: new Date(),
      // 添加用户信息，方便前端直接显示
      authorInfo: {
        nickName: user.userInfo?.nickName || '用户',
        avatarUrl: user.userInfo?.avatarUrl || ''
      }
    };
    
    const comment = await Comment.create(commentData);
    
    // 更新帖子评论数
    post.commentCount = (post.commentCount || 0) + 1;
    await post.save();
    
    console.log(`用户 ${openid} 评论成功，帖子 ${postId} 当前评论数: ${post.commentCount}`);
    
    // 记录评论者的经验值
    let commenterExpResult = null;
    try {
      commenterExpResult = await userLevelService.recordExp(openid, 'comment');
      console.log(`用户 ${openid} 评论获得经验: ${commenterExpResult.expAdded}`);
    } catch (expError) {
      console.error('记录评论经验值失败:', expError);
      // 经验记录失败不影响评论操作
    }
    
    // 记录被评论帖子作者的经验值（不给自己评论加经验）
    if (post.openid !== openid) {
      try {
        const authorExpResult = await userLevelService.recordExp(post.openid, 'beingCommented');
        console.log(`帖子作者 ${post.openid} 被评论获得经验: ${authorExpResult.expAdded}`);
      } catch (expError) {
        console.error('记录被评论经验值失败:', expError);
      }
      
      // 创建评论消息通知（给帖子作者）- 旧版评论接口只支持一级评论
      try {
        const message = new Message({
          type: 2, // 评论帖子
          senderId: openid,
          senderNickName: user.userInfo?.nickName || '用户',
          senderAvatar: user.userInfo?.avatarUrl || '',
          receiverId: post.openid, 
          postId: post._id,
          postTitle: post.title || (post.content ? post.content.substring(0, 20) : '帖子'),
          commentId: comment._id,
          content: content ? content.substring(0, 50) : '', // 评论内容截取前50个字符
          isRead: false,
          createTime: Date.now()
        });
        
        await message.save();
        console.log(`创建评论消息通知成功 (旧版接口): 用户 ${openid} 评论了帖子 ${postId}`);
      } catch (msgError) {
        console.error('创建评论消息通知失败 (旧版接口):', msgError);
        // 消息创建失败不影响评论操作
      }
    }
    
    const responseData = {
      id: comment._id,
      content: comment.content,
      createTime: comment.time,
      authorInfo: comment.authorInfo
    };
    
    // 如果有经验值增加结果，添加到返回数据中
    if (commenterExpResult) {
      responseData.expResult = {
        expAdded: commenterExpResult.expAdded,
        levelUp: commenterExpResult.levelUp,
        levelInfo: commenterExpResult.levelInfo
      };
    }
    
    res.json({
      code: 0,
      message: '评论成功',
      data: responseData
    });
  } catch (error) {
    console.error('添加评论失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// ===================== 消息通知相关接口 =====================

/**
 * 获取消息列表
 * GET /api/messages/list
 */
app.get('/api/messages/list', async (req, res) => {
  try {
    const { openid, page = 1, size = 20, types } = req.query;
    
    // 参数验证
    if (!openid) {
      return res.json({ code: 1001, message: '参数错误' });
    }
    
    // 构建查询条件（不再需要过滤isDeleted，因为已删除的消息已被物理删除）
    const query = {
      receiverId: openid
    };
    
    // 如果指定了消息类型
    if (types) {
      const typeArray = types.split(',').map(t => parseInt(t)).filter(t => !isNaN(t));
      if (typeArray.length > 0) {
      query.type = { $in: typeArray };
      }
    }
    
    // 分页参数
    const skip = (parseInt(page) - 1) * parseInt(size);
    
    // 查询消息列表
    const messages = await Message.find(query)
      .sort({ createTime: -1 }) // 按时间倒序
      .skip(skip)
      .limit(parseInt(size))
      .lean();
    
    // 查询总消息数
    const total = await Message.countDocuments(query);
    
    // 查询未读消息数
    const unread = await Message.countDocuments({ ...query, isRead: false });
    
    // 返回消息列表和分页信息
    return res.json({
      code: 0,
      message: 'success',
      data: {
        list: messages,
        total,
        unread,
        hasMore: skip + messages.length < total
      }
    });
  } catch (error) {
    console.error('获取消息列表失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

/**
 * 获取未读消息数量
 * GET /api/messages/unread/count
 */
app.get('/api/messages/unread/count', async (req, res) => {
  try {
    const { openid } = req.query;
    
    // 参数验证
    if (!openid) {
      return res.json({ code: 1001, message: '参数错误' });
    }
    
    // 查询未读消息数
    const count = await Message.countDocuments({
      receiverId: openid,
      isRead: false
    });
    
    // 返回未读数量
    return res.json({
      code: 0,
      message: 'success',
      data: { count }
    });
  } catch (error) {
    console.error('获取未读消息数量失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

/**
 * 标记消息为已读
 * POST /api/messages/read
 */
app.post('/api/messages/read', async (req, res) => {
  try {
    const { openid, messageId } = req.body;
    
    // 参数验证
    if (!openid || !messageId) {
      return res.json({ code: 1001, message: '参数错误' });
    }
    
    // 更新消息为已读
    await Message.updateOne(
      { _id: messageId, receiverId: openid },
      { $set: { isRead: true, updateTime: Date.now() } }
    );
    
    // 查询剩余未读消息数
    const unread = await Message.countDocuments({
      receiverId: openid,
      isRead: false
    });
    
    // 返回剩余未读数
    return res.json({
      code: 0,
      message: 'success',
      data: { unread }
    });
  } catch (error) {
    console.error('标记消息已读失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

/**
 * 标记所有消息为已读
 * POST /api/messages/read/all
 */
app.post('/api/messages/read/all', async (req, res) => {
  try {
    const { openid } = req.body;
    
    // 参数验证
    if (!openid) {
      return res.json({ code: 1001, message: '参数错误' });
    }
    
    // 更新所有消息为已读
    await Message.updateMany(
      { receiverId: openid, isRead: false },
      { $set: { isRead: true, updateTime: Date.now() } }
    );
    
    // 返回成功结果
    return res.json({
      code: 0,
      message: 'success',
      data: { unread: 0 }
    });
  } catch (error) {
    console.error('标记所有消息已读失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

/**
 * 删除消息
 * POST /api/messages/delete
 */
app.post('/api/messages/delete', async (req, res) => {
  try {
    const { openid, messageId } = req.body;
    
    // 参数验证
    if (!openid || !messageId) {
      return res.json({ code: 1001, message: '参数错误' });
    }
    
    // 查找消息，确保只能删除自己的消息
    const message = await Message.findOne({
      _id: messageId,
      receiverId: openid
    });
    
    if (!message) {
      return res.json({ code: 1004, message: '消息不存在或已被删除' });
    }
    
    // 物理删除消息（直接从数据库中删除，释放存储空间）
    await Message.deleteOne({ _id: messageId });
    
    // 返回成功结果
    return res.json({
      code: 0,
      message: 'success',
      data: { deletedMessageId: messageId }
    });
  } catch (error) {
    console.error('删除消息失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

/**
 * 数据库清理：删除所有逻辑删除的消息
 * POST /api/admin/cleanup-deleted-messages
 * 暂无调用************************
 * 注意：这是管理员接口，用于清理历史的逻辑删除数据
 */
app.post('/api/admin/cleanup-deleted-messages', async (req, res) => {
  // 管理员校验
  try {
    const { openid } = req.body || {};
    if (!openid) return res.status(401).json({ code: 401, message: '未提供管理员身份(openid)' });
    const adminUser = await User.findOne({ openid }).lean();
    if (!adminUser || !adminUser.isAdmin) return res.status(403).json({ code: 403, message: '无管理员权限' });
  } catch (e) {
    return res.status(500).json({ code: 500, message: '管理员校验失败' });
  }
  try {
    // 查询所有逻辑删除的消息数量
    const deletedCount = await Message.countDocuments({ isDeleted: true });
    
    if (deletedCount === 0) {
      return res.json({
        code: 0,
        message: '没有需要清理的消息',
        data: { deletedCount: 0 }
      });
    }
    
    // 物理删除所有逻辑删除的消息
    const result = await Message.deleteMany({ isDeleted: true });
    
    console.log(`数据库清理完成：删除了 ${result.deletedCount} 条逻辑删除的消息`);
    
    return res.json({
      code: 0,
      message: '清理完成',
      data: { 
        deletedCount: result.deletedCount,
        expectedCount: deletedCount
      }
    });
  } catch (error) {
    console.error('清理逻辑删除消息失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

// ===================== 搜索相关接口 =====================

/**
 * 搜索帖子API
 * GET /api/posts/search
 */
app.get('/api/posts/search', async (req, res) => {
  try {
    const { keyword, page = 1, pageSize = 10, type, startTime, endTime, openid } = req.query;
    
    // 参数验证
    if (!keyword) {
      return res.json({ code: 1001, message: '搜索关键词不能为空' });
    }
    
    // 将页码和每页数量转为数字
    const pageNum = parseInt(page);
    const size = parseInt(pageSize);
    const skip = (pageNum - 1) * size;
    
    console.log(`搜索请求: keyword=${keyword}, page=${pageNum}, pageSize=${size}, type=${type || '全部'}`);
    
    // 构建搜索条件
    // 方式2: 使用正则表达式进行模糊搜索（更灵活，支持中文部分匹配）
    const keywordRegex = new RegExp(keyword, 'i'); // i表示不区分大小写
    const query = {
      $and: [
        { state: '发布中' }, // 只搜索状态为"发布中"的帖子
        { $or: [
          { title: keywordRegex },
          { content: keywordRegex }
        ]}
      ]
    };
    
    // 如果指定了帖子类型，添加类型过滤
    if (type && ['二手转让', '交友', '求助', '信息分享'].includes(type)) {
      query.$and.push({ type });
    }
    
    // 如果指定了时间范围，添加时间过滤
    if (startTime || endTime) {
      const timeQuery = {};
      
      if (startTime) {
        timeQuery.$gte = new Date(parseInt(startTime));
      }
      
      if (endTime) {
        timeQuery.$lte = new Date(parseInt(endTime));
      }
      
      if (Object.keys(timeQuery).length > 0) {
        query.$and.push({ time: timeQuery });
      }
    }
    
    // 执行搜索查询
    const posts = await Post.find(query)
      .sort({ time: -1 }) // 按创建时间倒序排列
      .skip(skip)
      .limit(size)
      .lean(); // 转为普通JavaScript对象
    
    const total = await Post.countDocuments(query);
    console.log(`搜索结果: 找到 ${posts.length} 条记录，总共 ${total} 条`);
    
    // 查询用户点赞状态
    let userLikes = {};
    if (openid) {
      // 直接从帖子的likedBy数组中检查点赞状态
      posts.forEach(post => {
        const postIdStr = post._id.toString();
        if (post.likedBy && post.likedBy.includes(openid)) {
          userLikes[postIdStr] = true;
        }
      });
    }
    
    // 格式化返回数据，与前端期望的格式保持一致
    const formattedPosts = posts.map(post => {
      // 构建媒体列表
      const mediaList = post.images ? post.images.map(url => ({
        type: "image",
        url: url
      })) : [];
      
      // 使用帖子中存储的作者信息
      const authorInfo = post.authorInfo || {
        nickName: '用户',
        avatarUrl: ''
      };
      
      // 检查用户是否点赞
      const postId = post._id.toString();
      const isLiked = userLikes[postId] || false;
      
      return {
      id: post._id,
      title: post.title,
      content: post.content,
        createTime: post.time, // 使用time字段作为createTime返回
        likes: post.likeCount || 0,
        comments: post.commentCount || 0,
        avatarUrl: authorInfo.avatarUrl,
        nickName: authorInfo.nickName,
        userInfo: authorInfo,
        mediaList: mediaList,
        images: post.images || [],
      type: post.type,
        status: post.state === '发布中' ? 'active' : 'ended',
        isLiked: isLiked
      };
    });
    
    // 返回搜索结果，包含hasMore字段用于前端无限滚动判断
    return res.json({
      code: 0,
      message: 'success',
      data: {
        list: formattedPosts,
        total,
        hasMore: skip + posts.length < total
      }
    });
  } catch (error) {
    console.error('搜索帖子失败', error);
    return res.json({ code: 5000, message: '服务器内部错误' });
  }
});

// 添加文件访问调试接口
app.get('/api/debug/file-access', async (req, res) => {
  try {
    const { url } = req.query;
    if (!url) {
      return res.json({ code: 400, message: 'URL参数不能为空' });
    }
    
    // 解析文件路径
    const urlObj = new URL(url);
    const filePath = urlObj.pathname;
    const localPath = path.join(__dirname, '..', filePath);
    
    // 检查文件是否存在
    const exists = fs.existsSync(localPath);
    const stats = exists ? fs.statSync(localPath) : null;
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        url,
        filePath,
        localPath,
        exists,
        isFile: stats ? stats.isFile() : false,
        size: stats ? stats.size : 0,
        mtime: stats ? stats.mtime : null
      }
    });
  } catch (error) {
    console.error('文件访问调试失败:', error);
    res.json({ code: 500, message: '调试失败: ' + error.message });
  }
});

// ===================== 意见反馈相关接口 =====================

// 超级管理员功能已移除


/**
 * 提交意见反馈
 * POST /api/feedback/submit
 */
app.post('/api/feedback/submit', async (req, res) => {
  try {
    const { openid, type, content, contact } = req.body;

    // 参数验证
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }
    if (!type || ![1, 2, 3, 4].includes(parseInt(type))) {
      return res.status(400).json({ code: 400, message: '请选择反馈类型', data: null });
    }
    if (!content || content.trim().length === 0) {
      return res.status(400).json({ code: 400, message: '反馈内容不能为空', data: null });
    }
    if (content.length > 1000) {
      return res.status(400).json({ code: 400, message: '反馈内容不能超过1000字', data: null });
    }

    // 查找用户信息
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }

    // 创建反馈记录
    const feedback = new Feedback({
      openid,
      type: parseInt(type),
      content: content.trim(),
      contact: contact ? contact.trim() : '',
      userInfo: {
        nickName: user.userInfo?.nickName || '用户',
        avatarUrl: user.userInfo?.avatarUrl || ''
      }
    });

    await feedback.save();

    console.log(`用户 ${user.userInfo?.nickName || openid} 提交了反馈: ${content.substring(0, 50)}...`);

    res.json({
      code: 0,
      message: '反馈提交成功，感谢您的宝贵意见！',
      data: {
        feedbackId: feedback._id
      }
    });

  } catch (error) {
    console.error('提交反馈失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 获取用户的反馈历史
 * GET /api/feedback/my
 */
app.get('/api/feedback/my', async (req, res) => {
  try {
    const { openid, page = 1, pageSize = 10 } = req.query;

    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }

    const pageNum = parseInt(page);
    const size = parseInt(pageSize);
    const skip = (pageNum - 1) * size;

    // 获取反馈记录
    const feedbacks = await Feedback.find({ openid, userDeleted: { $ne: true } })
      .sort({ createTime: -1 })
      .skip(skip)
      .limit(size)
      .lean();

    const total = await Feedback.countDocuments({ openid, userDeleted: { $ne: true } });

    // 格式化反馈类型和状态
    const formatFeedbacks = feedbacks.map(item => ({
      ...item,
      typeText: getFeedbackTypeText(item.type),
      statusText: getFeedbackStatusText(item.status),
      createTimeText: new Date(item.createTime).toLocaleString('zh-CN')
    }));

    res.json({
      code: 0,
      message: 'success',
      data: {
        feedbacks: formatFeedbacks,
        total,
        hasMore: total > pageNum * size
      }
    });

  } catch (error) {
    console.error('获取反馈历史失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 删除用户自己的反馈
 * DELETE /api/feedback/:id?openid=xxx
 */
app.delete('/api/feedback/:id', async (req, res) => {
  try {
    const { id } = req.params;
    const openid = req.query.openid || req.body?.openid;

    if (!id || !openid) {
      return res.status(400).json({ code: 400, message: '参数缺失', data: null });
    }

    const feedback = await Feedback.findById(id);
    if (!feedback) {
      return res.status(404).json({ code: 404, message: '反馈不存在', data: null });
    }

    if (String(feedback.openid) !== String(openid)) {
      return res.status(403).json({ code: 403, message: '无权删除该反馈', data: null });
    }

    // 用户端软删除：仅标记 userDeleted=true；若管理端也已删除，则进行物理清除
    feedback.userDeleted = true;
    feedback.updateTime = new Date();
    await feedback.save();

    if (feedback.adminDeleted) {
      await Feedback.deleteOne({ _id: id });
      return res.json({ code: 0, message: '删除成功（已彻底清除）', data: null });
    }

    res.json({ code: 0, message: '删除成功（用户端隐藏）', data: null });
  } catch (error) {
    console.error('删除反馈失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 管理员获取反馈列表
 * GET /api/admin/feedbacks
 */
app.get('/api/admin/feedbacks', async (req, res) => {
  // 管理员校验（User.isAdmin=true）
  try {
    const { openid } = req.query;
    if (!openid) {
      return res.status(401).json({ code: 401, message: '未提供管理员身份(openid)' });
    }
    const adminUser = await User.findOne({ openid }).lean();

    if (!adminUser || (!adminUser.isAdmin && !adminUser.isSuperAdmin)) {
      return res.status(403).json({ code: 403, message: '无管理员权限' });
    }
  } catch (e) {
    return res.status(500).json({ code: 500, message: '管理员校验失败' });
  }
  try {
    const { page = 1, pageSize = 20, status, type, keyword } = req.query;

    const pageNum = parseInt(page);
    const size = parseInt(pageSize);
    const skip = (pageNum - 1) * size;

    // 构建查询条件
    const query = {};
    
    if (status !== undefined && status !== '') {
      query.status = parseInt(status);
    }
    
    if (type !== undefined && type !== '') {
      query.type = parseInt(type);
    }
    
    if (keyword) {
      query.$or = [
        { content: new RegExp(keyword, 'i') },
        { 'userInfo.nickName': new RegExp(keyword, 'i') }
      ];
    }

    // 管理端默认不显示已被管理端删除的记录
    query.adminDeleted = { $ne: true };

    const feedbacks = await Feedback.find(query)
      .sort({ createTime: -1 })
      .skip(skip)
      .limit(size)
      .lean();

    const total = await Feedback.countDocuments(query);

    // 格式化数据
    const formatFeedbacks = feedbacks.map(item => ({
      ...item,
      typeText: getFeedbackTypeText(item.type),
      statusText: getFeedbackStatusText(item.status),
      createTimeText: new Date(item.createTime).toLocaleString('zh-CN')
    }));

    res.json({
      code: 0,
      message: 'success',
      data: {
        feedbacks: formatFeedbacks,
        total,
        hasMore: total > pageNum * size
      }
    });

  } catch (error) {
    console.error('获取反馈列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 管理员回复反馈
 * POST /api/admin/feedbacks/:id/reply
 */
app.post('/api/admin/feedbacks/:id/reply', async (req, res) => {
  // 管理员校验（User.isAdmin=true）
  try {
    const { openid } = req.body || {};
    if (!openid) {
      return res.status(401).json({ code: 401, message: '未提供管理员身份(openid)' });
    }
    const adminUser = await User.findOne({ openid }).lean();
    if (!adminUser || (!adminUser.isAdmin && !adminUser.isSuperAdmin)) {
      return res.status(403).json({ code: 403, message: '无管理员权限' });
    }
  } catch (e) {
    return res.status(500).json({ code: 500, message: '管理员校验失败' });
  }
  try {
    const { id } = req.params;
    const { content, adminName = '管理员' } = req.body;

    if (!content || content.trim().length === 0) {
      return res.status(400).json({ code: 400, message: '回复内容不能为空', data: null });
    }

    const feedback = await Feedback.findById(id);
    if (!feedback) {
      return res.status(404).json({ code: 404, message: '反馈不存在', data: null });
    }

    // 更新反馈记录
    feedback.adminReply = {
      content: content.trim(),
      adminName,
      replyTime: new Date()
    };
    feedback.status = 2; // 已处理
    feedback.updateTime = new Date();

    await feedback.save();

    res.json({
      code: 0,
      message: '回复成功',
      data: null
    });

  } catch (error) {
    console.error('回复反馈失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 辅助函数：获取反馈类型文本
function getFeedbackTypeText(type) {
  const typeMap = {
    1: '功能建议',
    2: '问题反馈', 
    3: '内容投诉',
    4: '其他'
  };
  return typeMap[type] || '未知类型';
}

// 辅助函数：获取反馈状态文本
function getFeedbackStatusText(status) {
  const statusMap = {
    0: '待处理',
    1: '处理中',
    2: '已处理',
    3: '已关闭'
  };
  return statusMap[status] || '未知状态';
}

// 添加健康检查接口
app.get('/api/health', (req, res) => {
  res.json({
    code: 0,
    message: 'Server is running',
    data: {
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      env: process.env.NODE_ENV || 'development'
    }
  });
});

// ===================== 身份验证相关API =====================

// 配置身份证照片静态文件访问
app.use('/File/Identify', express.static(path.join(__dirname, '../File/Identify')));

/**
 * 获取用户身份验证状态
 * GET /api/identity/status?openid=xxx
 */
app.get('/api/identity/status', async (req, res) => {
  try {
    const { openid } = req.query;
    
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }
    
    // 查找用户的身份验证记录
    let verification = await IdentityVerification.findOne({ openid });
    
    if (!verification) {
      // 如果没有记录，创建一个默认记录
      verification = {
        status: 'not_verified',
        submitTime: null,
        reviewTime: null
      };
    }
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        status: verification.status,
        submitTime: verification.submitTime,
        reviewTime: verification.reviewTime,
        reviewRemark: verification.reviewRemark,
        rejectReason: verification.rejectReason
      }
    });
  } catch (error) {
    console.error('获取身份验证状态失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 上传身份证照片
 * POST /api/identity/upload
 */
app.post('/api/identity/upload', uploadIdentity.single('image'), async (req, res) => {
  try {
    const { openid, type } = req.body;
    
    if (!openid) {
      return res.status(400).json({ code: 400, message: 'openid不能为空', data: null });
    }
    
    if (!req.file) {
      return res.status(400).json({ code: 400, message: '请选择要上传的文件', data: null });
    }
    
    if (!type || !['id_front', 'id_back'].includes(type)) {
      return res.status(400).json({ code: 400, message: '无效的图片类型', data: null });
    }
    
    // 构建文件URL
    const protocol = req.get('x-forwarded-proto') || req.protocol || 'https';
    const host = req.get('x-forwarded-host') || req.get('host');
    const relativePath = `/File/Identify/${openid}/${req.file.filename}`;
    const imageUrl = `${protocol}://${host}${relativePath}`;
    
    res.json({
      code: 0,
      message: '上传成功',
      data: {
        imageUrl: imageUrl,
        filename: req.file.filename,
        type: type
      }
    });
  } catch (error) {
    console.error('上传身份证照片失败:', error);
    res.status(500).json({ code: 500, message: '上传失败', data: null });
  }
});

/**
 * 提交身份验证申请
 * POST /api/identity/submit
 */
app.post('/api/identity/submit', async (req, res) => {
  try {
    const { openid, name, idCard, phone, frontImage, backImage } = req.body;
    
    // 参数验证
    if (!openid || !name || !idCard || !phone || !frontImage || !backImage) {
      return res.status(400).json({ code: 400, message: '参数不完整', data: null });
    }
    
    // 检查用户是否存在
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ code: 404, message: '用户不存在', data: null });
    }
    
    // 查找现有的验证记录
    let verification = await IdentityVerification.findOne({ openid });
    
    if (verification) {
      // 如果已经有记录，更新记录
      verification.name = name;
      verification.idCard = idCard;
      verification.phone = phone;
      verification.frontImage = frontImage;
      verification.backImage = backImage;
      verification.status = 'pending';
      verification.submitTime = new Date();
      verification.reviewTime = null;
      verification.reviewerId = null;
      verification.reviewerName = null;
      verification.reviewRemark = null;
      verification.rejectReason = null;
      await verification.save();
    } else {
      // 创建新的验证记录
      verification = await IdentityVerification.create({
        openid,
        name,
        idCard,
        phone,
        frontImage,
        backImage,
        status: 'pending',
        submitTime: new Date()
      });
    }
    
    // 记录操作日志
    await IdentityAuditLog.create({
      applicationId: verification.id,
      reviewerId: openid,
      reviewerName: user.userInfo?.nickName || '用户',
      action: 'resubmit',
      previousStatus: 'not_verified',
      newStatus: 'pending',
      remark: '用户提交身份验证申请',
      operationTime: new Date(),
      ipAddress: req.ip,
      userAgent: req.get('User-Agent')
    });
    
    res.json({
      code: 0,
      message: '提交成功',
      data: {
        id: verification.id,
        status: verification.status,
        submitTime: verification.submitTime
      }
    });
  } catch (error) {
    console.error('提交身份验证申请失败:', error);
    res.status(500).json({ code: 500, message: '提交失败', data: null });
  }
});

/**
 * 获取身份验证审核列表（管理员）
 * GET /api/identity/audit/list
 */
app.get('/api/identity/audit/list', checkAdminPermission, async (req, res) => {
  try {
    const { pageNum = 1, pageSize = 10, status = 'all', keyword = '' } = req.query;
    
    const page = parseInt(pageNum);
    const size = parseInt(pageSize);
    const skip = (page - 1) * size;
    
    // 构建查询条件
    const query = {};
    
    if (status !== 'all') {
      query.status = status;
    }
    
    if (keyword) {
      query.$or = [
        { name: new RegExp(keyword, 'i') },
        { idCard: new RegExp(keyword, 'i') },
        { phone: new RegExp(keyword, 'i') }
      ];
    }
    
    // 查询验证记录
    const verifications = await IdentityVerification.find(query)
      .sort({ submitTime: -1, createdAt: -1 })
      .skip(skip)
      .limit(size);
    
    const total = await IdentityVerification.countDocuments(query);
    
    // 获取用户信息
    const enrichedList = await Promise.all(verifications.map(async (verification) => {
      const user = await User.findOne({ openid: verification.openid });
      return {
        id: verification.id,
        openid: verification.openid,
        name: verification.name,
        idCard: verification.idCard,
        phone: verification.phone,
        frontImage: verification.frontImage,
        backImage: verification.backImage,
        status: verification.status,
        submitTime: verification.submitTime,
        reviewTime: verification.reviewTime,
        reviewerId: verification.reviewerId,
        reviewerName: verification.reviewerName,
        reviewRemark: verification.reviewRemark,
        rejectReason: verification.rejectReason,
        userInfo: user ? {
          nickName: user.userInfo?.nickName || '未知用户',
          avatarUrl: user.userInfo?.avatarUrl || ''
        } : null
      };
    }));
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        list: enrichedList,
        total,
        pageNum: page,
        pageSize: size,
        hasMore: total > page * size
      }
    });
  } catch (error) {
    console.error('获取审核列表失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

/**
 * 提交审核结果（管理员）
 * POST /api/identity/audit/submit
 */
app.post('/api/identity/audit/submit', checkAdminPermission, async (req, res) => {
  try {
    console.log('收到审核提交请求:', req.body);
    const { reviewerOpenid, applicationId, action, remark } = req.body;
    
    // 参数验证
    if (!reviewerOpenid || !applicationId || !action || !remark) {
      console.error('参数不完整:', { reviewerOpenid, applicationId, action, remark });
      return res.status(400).json({ code: 400, message: '参数不完整', data: null });
    }
    
    if (!['approve', 'reject'].includes(action)) {
      return res.status(400).json({ code: 400, message: '无效的操作类型', data: null });
    }
    
    // 查找验证记录
    console.log('查找身份验证记录, applicationId:', applicationId);
    const verification = await IdentityVerification.findById(applicationId);
    if (!verification) {
      console.error('验证记录不存在, applicationId:', applicationId);
      return res.status(404).json({ code: 404, message: '验证记录不存在', data: null });
    }
    
    console.log('找到验证记录:', { id: verification.id, status: verification.status });
    if (verification.status !== 'pending') {
      console.error('记录状态不是pending:', verification.status);
      return res.status(400).json({ code: 400, message: '该记录已被审核', data: null });
    }
    
    // 查找审核人员信息
    const reviewer = await User.findOne({ openid: reviewerOpenid });
    if (!reviewer) {
      return res.status(404).json({ code: 404, message: '审核人员不存在', data: null });
    }
    
    // 更新验证记录
    const previousStatus = verification.status;
    const newStatus = action === 'approve' ? 'approved' : 'rejected';
    
    verification.status = newStatus;
    verification.reviewTime = new Date();
    verification.reviewerId = reviewerOpenid;
    verification.reviewerName = reviewer.userInfo?.nickName || '管理员';
    verification.reviewRemark = remark;
    
    if (action === 'reject') {
      verification.rejectReason = remark;
    }
    
    await verification.save();
    
    // 记录操作日志
    await IdentityAuditLog.create({
      applicationId: verification.id,
      reviewerId: reviewerOpenid,
      reviewerName: reviewer.userInfo?.nickName || '管理员',
      action: action,
      previousStatus: previousStatus,
      newStatus: newStatus,
      remark: remark,
      operationTime: new Date(),
      ipAddress: req.ip,
      userAgent: req.get('User-Agent')
    });
    
    res.json({
      code: 0,
      message: '审核完成',
      data: {
        id: verification.id,
        status: verification.status,
        reviewTime: verification.reviewTime,
        reviewRemark: verification.reviewRemark
      }
    });
  } catch (error) {
    console.error('提交审核结果失败:', error);
    res.status(500).json({ code: 500, message: '审核失败', data: null });
  }
});

/**
 * 获取审核操作历史记录（管理员）
 * GET /api/identity/audit/logs?applicationId=xxx
 */
app.get('/api/identity/audit/logs', checkAdminPermission, async (req, res) => {
  try {
    const { applicationId, pageNum = 1, pageSize = 20 } = req.query;
    
    if (!applicationId) {
      return res.status(400).json({ code: 400, message: 'applicationId不能为空', data: null });
    }
    
    const page = parseInt(pageNum);
    const size = parseInt(pageSize);
    const skip = (page - 1) * size;
    
    // 查询操作日志
    const logs = await IdentityAuditLog.find({ applicationId })
      .sort({ operationTime: -1 })
      .skip(skip)
      .limit(size);
    
    const total = await IdentityAuditLog.countDocuments({ applicationId });
    
    res.json({
      code: 0,
      message: 'success',
      data: {
        logs,
        total,
        pageNum: page,
        pageSize: size
      }
    });
  } catch (error) {
    console.error('获取审核日志失败:', error);
    res.status(500).json({ code: 500, message: '服务器错误', data: null });
  }
});

// 初始化定时任务
scheduleService.initScheduleTasks();

app.listen(4000, () => {
  console.log("server running port 4000!");
  console.log("File service configuration:");
  console.log("- Avatar path:", path.join(__dirname, '../File/Images/Avatar'));
  console.log("- PostImage path:", path.join(__dirname, '../File/Images/PostImage'));
  console.log("- Banners path:", path.join(__dirname, '../File/Images/Banners'));
  console.log("- Identity path:", path.join(__dirname, '../File/Identify'));
});


